[PATCH 08/12] sm4: add RISC-V Zvksed intrinsics implementation
Jussi Kivilinna
jussi.kivilinna at iki.fi
Sun Oct 11 19:23:17 CEST 2026
* cipher/Makefile.am: Add 'sm4-riscv-zvksed-zvkb.c' and
'sm4-riscv-zvksed-zvkb.h'.
(riscv_vector_crypto_sm4_cflags): New.
* cipher/sm4-riscv-zvksed-zvkb.c: New.
* cipher/sm4-riscv-zvksed-zvkb.h: New.
* cipher/sm4.c (USE_RISCV_V_CRYPTO): New.
(SM4_context) [USE_RISCV_V_CRYPTO]: Add 'use_riscv_zvksed'.
[USE_RISCV_V_CRYPTO] (_gcry_sm4_riscv_v_check_hw)
(_gcry_sm4_riscv_zvksed_expand_key, _gcry_sm4_riscv_zvksed_crypt)
(_gcry_sm4_riscv_zvksed_ctr_enc, _gcry_sm4_riscv_zvksed_cbc_dec)
(_gcry_sm4_riscv_zvksed_cfb_dec, sm4_riscv_zvksed_crypt_blk1_16): New.
(sm4_expand_key, sm4_encrypt, sm4_decrypt, sm4_get_crypt_blk1_16_fn)
(_gcry_sm4_ctr_enc, _gcry_sm4_cbc_dec, _gcry_sm4_cfb_dec)
(sm4_crypt_blk1_32) [USE_RISCV_V_CRYPTO]: Add RISC-V Zvksed code-path.
(sm4_setkey) [USE_RISCV_V_CRYPTO]: Enable new implementation if supported
by HW.
* configure.ac: Add 'sm4-riscv-zvksed-zvkb.lo'.
(GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST): Add SM4 intrinsics test.
(HAVE_BROKEN_VSM4R_VS_INTRINSIC): New check.
* doc/gcrypt.texi: Add "riscv-zvksed".
* src/g10lib.h [HAVE_CPU_ARCH_RISCV] (HWF_RISCV_ZVKSED): New.
(HWF_RISCV_ZVKSH): Move to bit 11.
* src/hwf-riscv.c (HWF_RISCV_HWPROBE_EXT_ZVKSED): New.
(hwprobe_features): Add Zvksed.
* src/hwfeatures.c (hwflist) [HAVE_CPU_ARCH_RISCV]: Add "riscv-zvksed".
--
Blocks are processed with LMUL=4 and tail with smallest LMUL that fits.
CTR, CBC decryption and CFB decryption have vector implementations,
other modes use generic bulk helpers.
Benchmark on SpacemiT K3, X100 core (out-of-order, VLEN=256):
Before:
SM4 | nanosecs/byte mebibytes/sec cycles/byte auto Mhz
ECB enc | 16.95 ns/B 56.27 MiB/s 33.84 c/B 1997
CBC enc | 19.86 ns/B 48.02 MiB/s 39.67 c/B 1997
CBC dec | 17.13 ns/B 55.66 MiB/s 34.23 c/B 1998
CFB dec | 17.16 ns/B 55.59 MiB/s 34.29 c/B 1999
CTR enc | 17.21 ns/B 55.43 MiB/s 34.36 c/B 1997
XTS enc | 17.23 ns/B 55.35 MiB/s 34.41 c/B 1997
GCM enc | 17.33 ns/B 55.02 MiB/s 34.62 c/B 1997
OCB enc | 17.47 ns/B 54.60 MiB/s 34.88 c/B 1997
After (CTR ~47x faster, CBC enc ~7.2x faster):
SM4 | nanosecs/byte mebibytes/sec cycles/byte auto Mhz
ECB enc | 0.407 ns/B 2345 MiB/s 0.812 c/B 1997
CBC enc | 2.75 ns/B 346.8 MiB/s 5.49 c/B 1997
CBC dec | 0.435 ns/B 2192 MiB/s 0.869 c/B 1997
CFB dec | 0.418 ns/B 2281 MiB/s 0.835 c/B 1997
CTR enc | 0.364 ns/B 2617 MiB/s 0.728 c/B 1997
XTS enc | 0.680 ns/B 1402 MiB/s 1.36 c/B 1997
GCM enc | 0.497 ns/B 1921 MiB/s 0.991 c/B 1997
OCB enc | 0.904 ns/B 1055 MiB/s 1.80 c/B 1997
Benchmark on SpacemiT K3, A100 core (in-order, VLEN=1024):
Before:
SM4 | nanosecs/byte mebibytes/sec cycles/byte auto Mhz
ECB enc | 23.12 ns/B 41.24 MiB/s 41.62 c/B 1800
CBC enc | 25.35 ns/B 37.62 MiB/s 45.63 c/B 1800
CBC dec | 23.47 ns/B 40.63 MiB/s 42.25 c/B 1800
CFB dec | 23.66 ns/B 40.31 MiB/s 42.58 c/B 1800
CTR enc | 23.73 ns/B 40.18 MiB/s 42.72 c/B 1800
XTS enc | 23.79 ns/B 40.08 MiB/s 42.82 c/B 1800
GCM enc | 25.22 ns/B 37.82 MiB/s 45.39 c/B 1800
OCB enc | 24.58 ns/B 38.80 MiB/s 44.24 c/B 1800
After (CTR ~56x faster, CBC enc ~2.2x faster):
SM4 | nanosecs/byte mebibytes/sec cycles/byte auto Mhz
ECB enc | 0.675 ns/B 1413 MiB/s 1.21 c/B 1800
CBC enc | 11.65 ns/B 81.83 MiB/s 20.98 c/B 1800
CBC dec | 0.507 ns/B 1882 MiB/s 0.912 c/B 1800
CFB dec | 0.498 ns/B 1913 MiB/s 0.897 c/B 1800
CTR enc | 0.423 ns/B 2254 MiB/s 0.762 c/B 1800
XTS enc | 1.35 ns/B 708.6 MiB/s 2.42 c/B 1800
GCM enc | 1.59 ns/B 598.5 MiB/s 2.87 c/B 1800
OCB enc | 2.32 ns/B 410.3 MiB/s 4.18 c/B 1800
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/Makefile.am | 12 +-
cipher/sm4-riscv-zvksed-zvkb.c | 322 +++++++++++++++++++++++++++++++++
cipher/sm4-riscv-zvksed-zvkb.h | 210 +++++++++++++++++++++
cipher/sm4.c | 108 +++++++++++
configure.ac | 64 +++++++
doc/gcrypt.texi | 1 +
src/g10lib.h | 3 +-
src/hwf-riscv.c | 2 +
src/hwfeatures.c | 1 +
9 files changed, 721 insertions(+), 2 deletions(-)
create mode 100644 cipher/sm4-riscv-zvksed-zvkb.c
create mode 100644 cipher/sm4-riscv-zvksed-zvkb.h
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 50509914..23c4655c 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -142,7 +142,7 @@ EXTRA_libcipher_la_SOURCES = \
sm4-intel-avx2-amd64.S sm4-intel-avx512-amd64.S \
sm4-gfni-avx2-amd64.S sm4-gfni-avx512-amd64.S \
sm4-aarch64.S sm4-armv8-aarch64-ce.S sm4-armv9-aarch64-sve-ce.S \
- sm4-ppc.c \
+ sm4-ppc.c sm4-riscv-zvksed-zvkb.c sm4-riscv-zvksed-zvkb.h \
sha1.c sha1-ssse3-amd64.S sha1-avx-amd64.S sha1-avx-bmi2-amd64.S \
sha1-avx2-bmi2-amd64.S sha1-armv7-neon.S sha1-armv8-aarch32-ce.S \
sha1-armv8-aarch64-ce.S sha1-intel-shaext.c \
@@ -474,6 +474,7 @@ 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_sm4_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvksed_zvkb
riscv_vector_crypto_gcm_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvkg_zvkb
else
riscv_vector_crypto_zvkb_cflags =
@@ -483,6 +484,7 @@ 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_sm4_cflags =
riscv_vector_crypto_gcm_cflags =
endif
@@ -549,3 +551,11 @@ sm3-riscv-zvksh-zvkb-m1.o: $(srcdir)/sm3-riscv-zvksh-zvkb-m1.c Makefile
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)
+
+sm4-riscv-zvksed-zvkb.o: $(srcdir)/sm4-riscv-zvksed-zvkb.c Makefile
+ `echo $(COMPILE) $(riscv_vector_crypto_sm4_cflags) $(custom_depflags) -c $< | $(instrumentation_munging) `
+ $(custom_depfile_o)
+
+sm4-riscv-zvksed-zvkb.lo: $(srcdir)/sm4-riscv-zvksed-zvkb.c Makefile
+ `echo $(LTCOMPILE) $(riscv_vector_crypto_sm4_cflags) $(custom_depflags) -c $< | $(instrumentation_munging) `
+ $(custom_depfile_lo)
diff --git a/cipher/sm4-riscv-zvksed-zvkb.c b/cipher/sm4-riscv-zvksed-zvkb.c
new file mode 100644
index 00000000..9bb525a0
--- /dev/null
+++ b/cipher/sm4-riscv-zvksed-zvkb.c
@@ -0,0 +1,322 @@
+/* sm4-riscv-zvksed-zvkb.c - RISC-V vector crypto implementation of SM4
+ * 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_SM4)
+
+#include "g10lib.h"
+#include "bufhelp.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 SM4_ROUND_KEY_VARIABLES \
+ vuint32m1_t rk0, rk1, rk2, rk3, rk4, rk5, rk6, rk7
+
+#define SM4_ROUND_KEY_PARAMS \
+ vuint32m1_t rk0, vuint32m1_t rk1, vuint32m1_t rk2, vuint32m1_t rk3, \
+ vuint32m1_t rk4, vuint32m1_t rk5, vuint32m1_t rk6, vuint32m1_t rk7
+
+#define SM4_ROUND_KEYS rk0, rk1, rk2, rk3, rk4, rk5, rk6, rk7
+
+#define SM4_LOAD_ROUND_KEYS(rk) \
+ rk0 = __riscv_vle32_v_u32m1(rk + 0 * 4, 4); \
+ rk1 = __riscv_vle32_v_u32m1(rk + 1 * 4, 4); \
+ rk2 = __riscv_vle32_v_u32m1(rk + 2 * 4, 4); \
+ rk3 = __riscv_vle32_v_u32m1(rk + 3 * 4, 4); \
+ rk4 = __riscv_vle32_v_u32m1(rk + 4 * 4, 4); \
+ rk5 = __riscv_vle32_v_u32m1(rk + 5 * 4, 4); \
+ rk6 = __riscv_vle32_v_u32m1(rk + 6 * 4, 4); \
+ rk7 = __riscv_vle32_v_u32m1(rk + 7 * 4, 4)
+
+#define SM4_NEXT_BLOCKS(n) \
+ in += (n) * 16; \
+ out += (n) * 16; \
+ nblocks -= (n)
+
+#define SM4_LMUL m1
+#define SM4_MASK64_T vbool64_t
+#include "sm4-riscv-zvksed-zvkb.h"
+
+#define SM4_LMUL m2
+#define SM4_MASK64_T vbool32_t
+#include "sm4-riscv-zvksed-zvkb.h"
+
+#define SM4_LMUL m4
+#define SM4_MASK64_T vbool16_t
+#include "sm4-riscv-zvksed-zvkb.h"
+
+
+unsigned int ASM_FUNC_ATTR_NOINLINE FUNC_ATTR_OPT_O2
+_gcry_sm4_riscv_zvksed_crypt (const u32 *rk, byte *out, const byte *in,
+ size_t nblocks)
+{
+ size_t max_blocks_m1 = __riscv_vsetvlmax_e32m1() / 4;
+ size_t max_blocks_m2 = max_blocks_m1 * 2;
+ size_t max_blocks_m4 = max_blocks_m1 * 4;
+ SM4_ROUND_KEY_VARIABLES;
+
+ SM4_LOAD_ROUND_KEYS(rk);
+
+ if (nblocks > max_blocks_m2)
+ {
+ vbool16_t even_m4 = even_mask_m4();
+
+ while (nblocks >= max_blocks_m4)
+ {
+ sm4_ecb_blocks_m4(SM4_ROUND_KEYS, even_m4, out, in, max_blocks_m4);
+ SM4_NEXT_BLOCKS(max_blocks_m4);
+ }
+ if (nblocks > max_blocks_m2)
+ {
+ sm4_ecb_blocks_m4(SM4_ROUND_KEYS, even_m4, out, in, nblocks);
+ SM4_NEXT_BLOCKS(nblocks);
+ }
+ }
+ if (nblocks > max_blocks_m1)
+ sm4_ecb_blocks_m2(SM4_ROUND_KEYS, even_mask_m2(), out, in, nblocks);
+ else if (nblocks)
+ sm4_ecb_blocks_m1(SM4_ROUND_KEYS, even_mask_m1(), out, in, nblocks);
+
+ clear_vec_regs();
+
+ return 0;
+}
+
+
+/* Caller handles carry beyond low 16 bits of counter. */
+void ASM_FUNC_ATTR_NOINLINE FUNC_ATTR_OPT_O2
+_gcry_sm4_riscv_zvksed_ctr_enc (const u32 *rk, byte *out, const byte *in,
+ byte *ctr, size_t nblocks)
+{
+ u64 ctr_lo = rol64(buf_get_be64(ctr + 0), 32);
+ u64 ctr_hi_noswap = buf_get_be64(ctr + 8);
+ u64 ctr_hi = rol64(ctr_hi_noswap, 32);
+ size_t max_blocks_m1 = __riscv_vsetvlmax_e32m1() / 4;
+ size_t max_blocks_m2 = max_blocks_m1 * 2;
+ size_t max_blocks_m4 = max_blocks_m1 * 4;
+ SM4_ROUND_KEY_VARIABLES;
+
+ SM4_LOAD_ROUND_KEYS(rk);
+
+ ctr[14] = (ctr_hi_noswap + nblocks) >> 8;
+ ctr[15] = (ctr_hi_noswap + nblocks) >> 0;
+
+ if (nblocks > max_blocks_m2)
+ {
+ vbool16_t even_m4 = even_mask_m4();
+ vuint64m4_t ctr_m4 = ctr_init_m4(even_m4, ctr_lo, ctr_hi);
+ vuint64m4_t inc_m4 = ctr_inc_m4(even_m4, max_blocks_m4);
+
+ while (nblocks >= max_blocks_m4)
+ {
+ sm4_ctr_blocks_m4(SM4_ROUND_KEYS, even_m4, &ctr_m4, inc_m4, out, in,
+ max_blocks_m4);
+ ctr_hi += (u64)max_blocks_m4 << 32;
+ SM4_NEXT_BLOCKS(max_blocks_m4);
+ }
+ if (nblocks > max_blocks_m2)
+ {
+ sm4_ctr_blocks_m4(SM4_ROUND_KEYS, even_m4, &ctr_m4, inc_m4, out, in,
+ nblocks);
+ ctr_hi += (u64)nblocks << 32;
+ SM4_NEXT_BLOCKS(nblocks);
+ }
+ }
+ if (nblocks > max_blocks_m1)
+ {
+ vbool32_t even_m2 = even_mask_m2();
+ vuint64m2_t ctr_m2 = ctr_init_m2(even_m2, ctr_lo, ctr_hi);
+
+ sm4_ctr_blocks_m2(SM4_ROUND_KEYS, even_m2, &ctr_m2,
+ ctr_inc_m2(even_m2, max_blocks_m2), out, in, nblocks);
+ }
+ else if (nblocks)
+ {
+ vbool64_t even_m1 = even_mask_m1();
+ vuint64m1_t ctr_m1 = ctr_init_m1(even_m1, ctr_lo, ctr_hi);
+
+ sm4_ctr_blocks_m1(SM4_ROUND_KEYS, even_m1, &ctr_m1,
+ ctr_inc_m1(even_m1, max_blocks_m1), out, in, nblocks);
+ }
+
+ clear_vec_regs();
+}
+
+
+void ASM_FUNC_ATTR_NOINLINE FUNC_ATTR_OPT_O2
+_gcry_sm4_riscv_zvksed_cbc_dec (const u32 *rk, byte *out, const byte *in,
+ byte *iv_arg, size_t nblocks)
+{
+ size_t max_blocks_m1 = __riscv_vsetvlmax_e32m1() / 4;
+ size_t max_blocks_m2 = max_blocks_m1 * 2;
+ size_t max_blocks_m4 = max_blocks_m1 * 4;
+ vuint32m1_t iv;
+ SM4_ROUND_KEY_VARIABLES;
+
+ SM4_LOAD_ROUND_KEYS(rk);
+
+ iv = load_u32_m1(iv_arg, 4);
+
+ if (nblocks > max_blocks_m2)
+ {
+ vbool16_t even_m4 = even_mask_m4();
+ vuint32m4_t ivs_m4 = __riscv_vundefined_u32m4();
+
+ while (nblocks >= max_blocks_m4)
+ {
+ sm4_cbc_dec_blocks_m4(SM4_ROUND_KEYS, even_m4, &iv, &ivs_m4, out, in,
+ max_blocks_m4);
+ SM4_NEXT_BLOCKS(max_blocks_m4);
+ }
+ if (nblocks > max_blocks_m2)
+ {
+ sm4_cbc_dec_blocks_m4(SM4_ROUND_KEYS, even_m4, &iv, &ivs_m4, out, in,
+ nblocks);
+ SM4_NEXT_BLOCKS(nblocks);
+ }
+ }
+ if (nblocks > max_blocks_m1)
+ {
+ vuint32m2_t ivs_m2 = __riscv_vundefined_u32m2();
+
+ sm4_cbc_dec_blocks_m2(SM4_ROUND_KEYS, even_mask_m2(), &iv, &ivs_m2, out,
+ in, nblocks);
+ }
+ else if (nblocks)
+ {
+ vuint32m1_t ivs_m1 = __riscv_vundefined_u32m1();
+
+ sm4_cbc_dec_blocks_m1(SM4_ROUND_KEYS, even_mask_m1(), &iv, &ivs_m1, out,
+ in, nblocks);
+ }
+
+ store_u32_m1(iv_arg, iv, 4);
+
+ clear_vec_regs();
+}
+
+
+void ASM_FUNC_ATTR_NOINLINE FUNC_ATTR_OPT_O2
+_gcry_sm4_riscv_zvksed_cfb_dec (const u32 *rk, byte *out, const byte *in,
+ byte *iv_arg, size_t nblocks)
+{
+ size_t max_blocks_m1 = __riscv_vsetvlmax_e32m1() / 4;
+ size_t max_blocks_m2 = max_blocks_m1 * 2;
+ size_t max_blocks_m4 = max_blocks_m1 * 4;
+ vuint32m1_t iv;
+ SM4_ROUND_KEY_VARIABLES;
+
+ SM4_LOAD_ROUND_KEYS(rk);
+
+ iv = load_u32_m1(iv_arg, 4);
+
+ if (nblocks > max_blocks_m2)
+ {
+ vbool16_t even_m4 = even_mask_m4();
+ vuint32m4_t ivs_m4 = __riscv_vundefined_u32m4();
+
+ while (nblocks >= max_blocks_m4)
+ {
+ sm4_cfb_dec_blocks_m4(SM4_ROUND_KEYS, even_m4, &iv, &ivs_m4, out, in,
+ max_blocks_m4);
+ SM4_NEXT_BLOCKS(max_blocks_m4);
+ }
+ if (nblocks > max_blocks_m2)
+ {
+ sm4_cfb_dec_blocks_m4(SM4_ROUND_KEYS, even_m4, &iv, &ivs_m4, out, in,
+ nblocks);
+ SM4_NEXT_BLOCKS(nblocks);
+ }
+ }
+ if (nblocks > max_blocks_m1)
+ {
+ vuint32m2_t ivs_m2 = __riscv_vundefined_u32m2();
+
+ sm4_cfb_dec_blocks_m2(SM4_ROUND_KEYS, even_mask_m2(), &iv, &ivs_m2, out,
+ in, nblocks);
+ }
+ else if (nblocks)
+ {
+ vuint32m1_t ivs_m1 = __riscv_vundefined_u32m1();
+
+ sm4_cfb_dec_blocks_m1(SM4_ROUND_KEYS, even_mask_m1(), &iv, &ivs_m1, out,
+ in, nblocks);
+ }
+
+ store_u32_m1(iv_arg, iv, 4);
+
+ clear_vec_regs();
+}
+
+
+#define SM4_EXPAND_KEY_ROUNDS(rnd) \
+ k = __riscv_vsm4k_vi_u32m1(k, rnd, vl); \
+ __riscv_vse32_v_u32m1(rk_enc + (rnd) * 4, k, vl); \
+ __riscv_vsse32_v_u32m1(rk_dec + 31 - (rnd) * 4, -4, k, vl)
+
+void ASM_FUNC_ATTR_NOINLINE FUNC_ATTR_OPT_O2
+_gcry_sm4_riscv_zvksed_expand_key (const byte *key, u32 *rk_enc, u32 *rk_dec,
+ const u32 *fk)
+{
+ size_t vl = 4;
+ vuint32m1_t k;
+
+ k = __riscv_vrev8_v_u32m1(load_u32_m1(key, vl), vl);
+ k = __riscv_vxor_vv_u32m1(k, __riscv_vle32_v_u32m1(fk, vl), vl);
+
+ SM4_EXPAND_KEY_ROUNDS(0);
+ SM4_EXPAND_KEY_ROUNDS(1);
+ SM4_EXPAND_KEY_ROUNDS(2);
+ SM4_EXPAND_KEY_ROUNDS(3);
+ SM4_EXPAND_KEY_ROUNDS(4);
+ SM4_EXPAND_KEY_ROUNDS(5);
+ SM4_EXPAND_KEY_ROUNDS(6);
+ SM4_EXPAND_KEY_ROUNDS(7);
+
+ clear_vec_regs();
+}
+
+
+unsigned int ASM_FUNC_ATTR FUNC_ATTR_OPT_O2
+_gcry_sm4_riscv_v_check_hw(void)
+{
+ return (__riscv_vsetvl_e32m1(4) == 4);
+}
+
+#endif /* HAVE_COMPATIBLE_CC_RISCV_VECTOR_INTRINSICS */
diff --git a/cipher/sm4-riscv-zvksed-zvkb.h b/cipher/sm4-riscv-zvksed-zvkb.h
new file mode 100644
index 00000000..38e9b825
--- /dev/null
+++ b/cipher/sm4-riscv-zvksed-zvkb.h
@@ -0,0 +1,210 @@
+/* sm4-riscv-zvksed-zvkb.h - RISC-V vector crypto SM4 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 SM4_LMUL and SM4_MASK64_T set. */
+
+#define CAT_(a, b) a##b
+#define CAT(a, b) CAT_(a, b)
+
+#define FN(name) CAT(name##_, SM4_LMUL)
+#define V32(name) CAT(__riscv_##name##_u32, SM4_LMUL)
+#define V64(name) CAT(__riscv_##name##_u64, SM4_LMUL)
+#define V8(name) CAT(__riscv_##name##_u8, SM4_LMUL)
+#define VSETVLMAX_E64() CAT(__riscv_vsetvlmax_e64, SM4_LMUL)()
+#define VEC32_T CAT(CAT(vuint32, SM4_LMUL), _t)
+#define VEC64_T CAT(CAT(vuint64, SM4_LMUL), _t)
+#define MASK64_T SM4_MASK64_T
+
+#define SET_IV_m1(ivs, iv) (iv)
+#define SET_IV_m2(ivs, iv) __riscv_vset(ivs, 0, iv)
+#define SET_IV_m4(ivs, iv) __riscv_vset(ivs, 0, iv)
+#define SET_IV(ivs, iv) CAT(SET_IV_, SM4_LMUL)(ivs, iv)
+
+
+static ASM_FUNC_ATTR_INLINE VEC32_T
+FN(load_u32) (const byte *p, size_t vl)
+{
+#ifdef RVV_UNALIGNED_NOT_ALLOWED
+ return V32(vreinterpret)(V8(vle8_v)(p, vl * 4));
+#else
+ return V32(vle32_v)((const void *)p, vl);
+#endif
+}
+
+static ASM_FUNC_ATTR_INLINE void
+FN(store_u32) (byte *p, VEC32_T v, size_t vl)
+{
+#ifdef RVV_UNALIGNED_NOT_ALLOWED
+ __riscv_vse8(p, V8(vreinterpret)(v), vl * 4);
+#else
+ __riscv_vse32((u32 *)(void *)p, v, vl);
+#endif
+}
+
+static ASM_FUNC_ATTR_INLINE MASK64_T
+FN(even_mask) (void)
+{
+ size_t vl64 = VSETVLMAX_E64();
+
+ return __riscv_vmseq(__riscv_vand(V64(vid_v)(vl64), 1, vl64), 0, vl64);
+}
+
+/* Returns { ctr_lo, ctr_hi + (0 << 32), ctr_lo, ctr_hi + (1 << 32),
+ * ctr_lo, ctr_hi + (2 << 32), ... }. */
+static ASM_FUNC_ATTR_INLINE VEC64_T
+FN(ctr_init) (MASK64_T even, u64 ctr_lo, u64 ctr_hi)
+{
+ size_t vl64 = VSETVLMAX_E64();
+ VEC64_T c, offs;
+
+ offs = __riscv_vsll(__riscv_vsrl(V64(vid_v)(vl64), 1, vl64), 32, vl64);
+ offs = __riscv_vmerge(offs, 0, even, vl64);
+ c = V64(vmv_v_x)(ctr_hi, vl64);
+ c = __riscv_vmerge(c, ctr_lo, even, vl64);
+ return __riscv_vadd(c, offs, vl64);
+}
+
+/* Returns { 0, nblocks << 32, 0, nblocks << 32, ... }. */
+static ASM_FUNC_ATTR_INLINE VEC64_T
+FN(ctr_inc) (MASK64_T even, size_t nblocks)
+{
+ size_t vl64 = VSETVLMAX_E64();
+
+ return __riscv_vmerge(V64(vmv_v_x)((u64)nblocks << 32, vl64), 0, even,
+ vl64);
+}
+
+static ASM_FUNC_ATTR_INLINE VEC32_T
+FN(sm4_crypt) (SM4_ROUND_KEY_PARAMS, MASK64_T even, VEC32_T x, size_t vl)
+{
+ size_t vl64 = vl / 2;
+ VEC64_T t, y;
+
+#ifdef HAVE_BROKEN_VSM4R_VS_INTRINSIC
+ asm ( "vsetvli zero,%[vl],e32," STR2(SM4_LMUL) ",ta,ma;\n\t"
+ "vsm4r.vs %[x],%[rk0];\n\t"
+ "vsm4r.vs %[x],%[rk1];\n\t"
+ "vsm4r.vs %[x],%[rk2];\n\t"
+ "vsm4r.vs %[x],%[rk3];\n\t"
+ "vsm4r.vs %[x],%[rk4];\n\t"
+ "vsm4r.vs %[x],%[rk5];\n\t"
+ "vsm4r.vs %[x],%[rk6];\n\t"
+ "vsm4r.vs %[x],%[rk7];\n\t"
+ : [x] "+vr" (x)
+ : [vl] "r" (vl),
+ [rk0] "vr" (rk0), [rk1] "vr" (rk1), [rk2] "vr" (rk2),
+ [rk3] "vr" (rk3), [rk4] "vr" (rk4), [rk5] "vr" (rk5),
+ [rk6] "vr" (rk6), [rk7] "vr" (rk7)
+ : "vl", "vtype", "memory");
+#else
+ x = __riscv_vsm4r_vs(x, rk0, vl);
+ x = __riscv_vsm4r_vs(x, rk1, vl);
+ x = __riscv_vsm4r_vs(x, rk2, vl);
+ x = __riscv_vsm4r_vs(x, rk3, vl);
+ x = __riscv_vsm4r_vs(x, rk4, vl);
+ x = __riscv_vsm4r_vs(x, rk5, vl);
+ x = __riscv_vsm4r_vs(x, rk6, vl);
+ x = __riscv_vsm4r_vs(x, rk7, vl);
+#endif
+
+ t = __riscv_vrev8(V64(vreinterpret)(x), vl64);
+ y = __riscv_vslide1up(t, 0, vl64);
+ y = __riscv_vslidedown_mu(even, y, t, 1, vl64);
+ return V32(vreinterpret)(y);
+}
+
+static ASM_FUNC_ATTR_INLINE void
+FN(sm4_ecb_blocks) (SM4_ROUND_KEY_PARAMS, MASK64_T even, byte *out,
+ const byte *in, size_t n)
+{
+ size_t vl = n * 4;
+ VEC32_T x;
+
+ x = __riscv_vrev8(FN(load_u32)(in, vl), vl);
+ x = FN(sm4_crypt)(SM4_ROUND_KEYS, even, x, vl);
+ FN(store_u32)(out, x, vl);
+}
+
+static ASM_FUNC_ATTR_INLINE void
+FN(sm4_ctr_blocks) (SM4_ROUND_KEY_PARAMS, MASK64_T even, VEC64_T *ctr,
+ VEC64_T inc, byte *out, const byte *in, size_t n)
+{
+ size_t vl = n * 4;
+ size_t vl64 = n * 2;
+ VEC32_T x, d;
+
+ d = FN(load_u32)(in, vl);
+ x = V32(vreinterpret)(*ctr);
+ *ctr = __riscv_vadd(*ctr, inc, vl64);
+
+ x = FN(sm4_crypt)(SM4_ROUND_KEYS, even, x, vl);
+ x = __riscv_vxor(x, d, vl);
+ FN(store_u32)(out, x, vl);
+}
+
+static ASM_FUNC_ATTR_INLINE void
+FN(sm4_cbc_dec_blocks) (SM4_ROUND_KEY_PARAMS, MASK64_T even, vuint32m1_t *iv,
+ VEC32_T *ivs, byte *out, const byte *in, size_t n)
+{
+ size_t vl = n * 4;
+ VEC32_T d, x;
+
+ d = FN(load_u32)(in, vl);
+ *ivs = __riscv_vslideup(SET_IV(*ivs, *iv), d, 4, vl);
+ *iv = load_u32_m1(in + (n - 1) * 16, 4);
+
+ x = __riscv_vrev8(d, vl);
+ x = FN(sm4_crypt)(SM4_ROUND_KEYS, even, x, vl);
+ x = __riscv_vxor(x, *ivs, vl);
+ FN(store_u32)(out, x, vl);
+}
+
+static ASM_FUNC_ATTR_INLINE void
+FN(sm4_cfb_dec_blocks) (SM4_ROUND_KEY_PARAMS, MASK64_T even, vuint32m1_t *iv,
+ VEC32_T *ivs, byte *out, const byte *in, size_t n)
+{
+ size_t vl = n * 4;
+ VEC32_T d, x;
+
+ d = FN(load_u32)(in, vl);
+ *ivs = __riscv_vslideup(SET_IV(*ivs, *iv), d, 4, vl);
+ *iv = load_u32_m1(in + (n - 1) * 16, 4);
+
+ x = __riscv_vrev8(*ivs, vl);
+ x = FN(sm4_crypt)(SM4_ROUND_KEYS, even, x, vl);
+ x = __riscv_vxor(x, d, vl);
+ FN(store_u32)(out, x, vl);
+}
+
+#undef SET_IV
+#undef SET_IV_m4
+#undef SET_IV_m2
+#undef SET_IV_m1
+#undef MASK64_T
+#undef VEC64_T
+#undef VEC32_T
+#undef VSETVLMAX_E64
+#undef V8
+#undef V64
+#undef V32
+#undef FN
+#undef CAT
+#undef CAT_
+#undef SM4_MASK64_T
+#undef SM4_LMUL
diff --git a/cipher/sm4.c b/cipher/sm4.c
index 58aaea10..95cabdf3 100644
--- a/cipher/sm4.c
+++ b/cipher/sm4.c
@@ -142,6 +142,15 @@
# define USE_PPC_CRYPTO 1
#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
+
static const char *sm4_selftest (void);
static void _gcry_sm4_ctr_enc (void *context, unsigned char *ctr,
@@ -216,6 +225,9 @@ typedef struct
unsigned int use_ppc8le:1;
unsigned int use_ppc9le:1;
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ unsigned int use_riscv_zvksed:1;
+#endif
#ifdef ASM_FUNC_ABI
unsigned int ocb_crypt_blk_init:1;
unsigned int ocb_auth_blk_init:1;
@@ -756,6 +768,36 @@ sm4_ppc9le_crypt_blk1_16(void *rk, byte *out, const byte *in, size_t num_blks)
}
#endif /* USE_PPC_CRYPTO */
+#ifdef USE_RISCV_V_CRYPTO
+extern unsigned int _gcry_sm4_riscv_v_check_hw(void);
+
+extern void _gcry_sm4_riscv_zvksed_expand_key(const byte *key, u32 *rk_enc,
+ u32 *rk_dec, const u32 *fk);
+
+extern unsigned int _gcry_sm4_riscv_zvksed_crypt(const u32 *rk, byte *out,
+ const byte *in,
+ size_t num_blks);
+
+extern void _gcry_sm4_riscv_zvksed_ctr_enc(const u32 *rk_enc, byte *out,
+ const byte *in, byte *ctr,
+ size_t nblocks);
+
+extern void _gcry_sm4_riscv_zvksed_cbc_dec(const u32 *rk_dec, byte *out,
+ const byte *in, byte *iv,
+ size_t nblocks);
+
+extern void _gcry_sm4_riscv_zvksed_cfb_dec(const u32 *rk_enc, byte *out,
+ const byte *in, byte *iv,
+ size_t nblocks);
+
+static inline unsigned int
+sm4_riscv_zvksed_crypt_blk1_16(void *rk, byte *out, const byte *in,
+ size_t num_blks)
+{
+ return _gcry_sm4_riscv_zvksed_crypt(rk, out, in, num_blks);
+}
+#endif /* USE_RISCV_V_CRYPTO */
+
static inline void prefetch_sbox_table(void)
{
const volatile byte *vtab = (void *)&sbox_table.S[0];
@@ -870,6 +912,15 @@ sm4_expand_key (SM4_context *ctx, const byte *key)
}
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ if (ctx->use_riscv_zvksed)
+ {
+ _gcry_sm4_riscv_zvksed_expand_key (key, ctx->rkey_enc, ctx->rkey_dec,
+ fk);
+ return;
+ }
+#endif
+
prefetch_sbox_table ();
rk[0] = buf_get_be32(key + 4 * 0) ^ fk[0];
@@ -953,6 +1004,14 @@ sm4_setkey (void *context, const byte *key, const unsigned keylen,
ctx->use_ppc8le = (hwf & HWF_PPC_VCRYPTO) != 0;
ctx->use_ppc9le = (hwf & HWF_PPC_VCRYPTO) && (hwf & HWF_PPC_ARCH_3_00);
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ ctx->use_riscv_zvksed = (hwf & HWF_RISCV_IMAFDC)
+ && (hwf & HWF_RISCV_B) /* Mandatory in RVA23U64 */
+ && (hwf & HWF_RISCV_V) /* Mandatory in RVA23U64 */
+ && (hwf & HWF_RISCV_ZVKB) /* Mandatory in RVA23U64 (Zvbb) */
+ && (hwf & HWF_RISCV_ZVKSED) /* Optional in RVA23U64 (Zvks) */
+ && _gcry_sm4_riscv_v_check_hw();
+#endif
#ifdef USE_GFNI_AVX2
if (ctx->use_gfni_avx2)
@@ -1056,6 +1115,11 @@ sm4_encrypt (void *context, byte *outbuf, const byte *inbuf)
return sm4_armv8_ce_crypt_blk1_16(ctx->rkey_enc, outbuf, inbuf, 1);
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ if (ctx->use_riscv_zvksed)
+ return sm4_riscv_zvksed_crypt_blk1_16(ctx->rkey_enc, outbuf, inbuf, 1);
+#endif
+
prefetch_sbox_table ();
return sm4_do_crypt (ctx->rkey_enc, outbuf, inbuf);
@@ -1086,6 +1150,11 @@ sm4_decrypt (void *context, byte *outbuf, const byte *inbuf)
return sm4_armv8_ce_crypt_blk1_16(ctx->rkey_dec, outbuf, inbuf, 1);
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ if (ctx->use_riscv_zvksed)
+ return sm4_riscv_zvksed_crypt_blk1_16(ctx->rkey_dec, outbuf, inbuf, 1);
+#endif
+
prefetch_sbox_table ();
return sm4_do_crypt (ctx->rkey_dec, outbuf, inbuf);
@@ -1232,6 +1301,12 @@ sm4_get_crypt_blk1_16_fn(SM4_context *ctx)
{
return &sm4_ppc8le_crypt_blk1_16;
}
+#endif
+#ifdef USE_RISCV_V_CRYPTO
+ else if (ctx->use_riscv_zvksed)
+ {
+ return &sm4_riscv_zvksed_crypt_blk1_16;
+ }
#endif
else
{
@@ -1364,6 +1439,15 @@ _gcry_sm4_ctr_enc(void *context, unsigned char *ctr,
}
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ if (ctx->use_riscv_zvksed)
+ {
+ /* Process all blocks at a time. */
+ _gcry_sm4_riscv_zvksed_ctr_enc(ctx->rkey_enc, outbuf, inbuf, ctr, nblocks);
+ nblocks = 0;
+ }
+#endif
+
#ifdef USE_ARM_CE
if (ctx->use_arm_ce)
{
@@ -1543,6 +1627,15 @@ _gcry_sm4_cbc_dec(void *context, unsigned char *iv,
}
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ if (ctx->use_riscv_zvksed)
+ {
+ /* Process all blocks at a time. */
+ _gcry_sm4_riscv_zvksed_cbc_dec(ctx->rkey_dec, outbuf, inbuf, iv, nblocks);
+ nblocks = 0;
+ }
+#endif
+
#ifdef USE_ARM_CE
if (ctx->use_arm_ce)
{
@@ -1722,6 +1815,15 @@ _gcry_sm4_cfb_dec(void *context, unsigned char *iv,
}
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ if (ctx->use_riscv_zvksed)
+ {
+ /* Process all blocks at a time. */
+ _gcry_sm4_riscv_zvksed_cfb_dec(ctx->rkey_enc, outbuf, inbuf, iv, nblocks);
+ nblocks = 0;
+ }
+#endif
+
#ifdef USE_ARM_CE
if (ctx->use_arm_ce)
{
@@ -1806,6 +1908,12 @@ sm4_crypt_blk1_32 (SM4_context *ctx, byte *outbuf, const byte *inbuf,
return 0;
}
#endif
+#ifdef USE_RISCV_V_CRYPTO
+ if (ctx->use_riscv_zvksed)
+ {
+ return _gcry_sm4_riscv_zvksed_crypt (rk, outbuf, inbuf, num_blks);
+ }
+#endif
if (num_blks > 16)
{
diff --git a/configure.ac b/configure.ac
index a6b1f325..b10af44c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3054,6 +3054,15 @@ m4_define([GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST],
e = __riscv_vsm3c_vi_u32m1(e, g, 31, vl);
__riscv_vse32_v_u32m1(ptr + 0 * vl, e, vl);
}
+ void test_sm4(unsigned int *ptr)
+ {
+ int vl = __riscv_vsetvl_e32m4 (16);
+ vuint32m1_t a = __riscv_vle32_v_u32m1(ptr + 0 * vl, 4);
+ vuint32m4_t b = __riscv_vle32_v_u32m4(ptr + 1 * vl, vl);
+ vuint32m1_t c = __riscv_vsm4k_vi_u32m1(a, 7, 4);
+ vuint32m4_t d = __riscv_vsm4r_vs_u32m1_u32m4(b, c, vl);
+ __riscv_vse32_v_u32m4(ptr + 0 * vl, d, vl);
+ }
void test_rev8(unsigned int *ptr)
{
int vl = __riscv_vsetvl_e32m1 (4);
@@ -3093,6 +3102,7 @@ m4_define([GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST],
test_aes_crypt(buf);
test_ghash(buf);
test_sm3(buf);
+ test_sm4(buf);
test_rev8(buf);
test_rotate(buf);
test_inline_vec_asm(buf);
@@ -3254,6 +3264,56 @@ EOF
CFLAGS=$_gcc_cflags_save;
fi
+#
+# Check whether compiler has working RISC-V vector __riscv_vsm4r_vs intrinsics
+#
+# Same GCC issue as with __riscv_vaes*_vs intrinsics above, 'vsetvli' is
+# generated with 'm1' LMUL instead of 'mX' for __riscv_vsm4r_vs_u32m1_u32mX.
+#
+if test "$gcry_cv_cc_riscv_vector_crypto_intrinsics" = "yes" ||
+ test "$gcry_cv_cc_riscv_vector_crypto_intrinsics_cflags" = "yes"; then
+
+ # Setup flags for test.
+ _gcc_cflags_save=$CFLAGS
+ if test "$gcry_cv_cc_riscv_vector_crypto_intrinsics_cflags" = "yes"; then
+ CFLAGS="$CFLAGS -O2 -march=$MARCH_RVA23U64_WITH_VEC_CRYPTO"
+ else
+ CFLAGS="$CFLAGS -O2"
+ fi
+
+ # Disable LTO optimization for following check to generate
+ # RISC-V instructions in compiler output
+ CFLAGS="$CFLAGS -fno-lto"
+
+ AC_CACHE_CHECK([whether compiler has working RISC-V __riscv_vsm4r_vs intrinsics],
+ [gcry_cv_riscv_vsm4r_vs_intrinsics_work],
+ [gcry_cv_riscv_vsm4r_vs_intrinsics_work=no
+ cat > conftest.c <<EOF
+#include <riscv_vector.h>
+vuint32m4_t test_fn(vuint32m4_t a, vuint32m1_t b, int vl)
+{
+ /* This intrinsic should result in a 'vsetvli' with m4 */
+ return __riscv_vsm4r_vs_u32m1_u32m4(a, b, vl);
+}
+EOF
+
+ if $CC $CFLAGS -S conftest.c -o conftest.s >&5 2>&5; then
+ if grep -E 'vsetvli.*,[[[:space:]]]*m4[[[:space:]]]*,' conftest.s >/dev/null 2>&1; then
+ gcry_cv_riscv_vsm4r_vs_intrinsics_work=yes
+ fi
+ fi
+ rm -f conftest.*
+ ])
+
+ if test "$gcry_cv_riscv_vsm4r_vs_intrinsics_work" = "no"; then
+ AC_DEFINE([HAVE_BROKEN_VSM4R_VS_INTRINSIC], [1],
+ [Define to 1 if __riscv_vsm4r_vs intrinsics are broken])
+ fi
+
+ # Restore flags.
+ CFLAGS=$_gcc_cflags_save;
+fi
+
#######################################
#### Checks for library functions. ####
@@ -3973,6 +4033,10 @@ if test "$found" = "1" ; then
# Build with the ppc64le vector implementation
GCRYPT_ASM_CIPHERS="$GCRYPT_ASM_CIPHERS sm4-ppc.lo"
;;
+ riscv64-*-*)
+ # Build with the RISC-V vector cryptography implementation
+ GCRYPT_ASM_CIPHERS="$GCRYPT_ASM_CIPHERS sm4-riscv-zvksed-zvkb.lo"
+ ;;
esac
fi
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 613920d8..18a6f24c 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-zvksed
@item riscv-zvksh
@end table
diff --git a/src/g10lib.h b/src/g10lib.h
index 8a2d706c..a9c18db6 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -288,7 +288,8 @@ 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)
+#define HWF_RISCV_ZVKSED (1 << 10)
+#define HWF_RISCV_ZVKSH (1 << 11)
#endif
diff --git a/src/hwf-riscv.c b/src/hwf-riscv.c
index adec2b02..192ab031 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_ZVKSED (1U << 24)
#define HWF_RISCV_HWPROBE_EXT_ZVKSH (1U << 25)
#define HWF_RISCV_HWPROBE_EXT_ZICOND (U64_C(1) << 35)
@@ -228,6 +229,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_ZVKSED, HWF_RISCV_ZVKSED },
{ HWF_RISCV_HWPROBE_EXT_ZVKSH, HWF_RISCV_ZVKSH },
};
diff --git a/src/hwfeatures.c b/src/hwfeatures.c
index 2f836079..3067ee86 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_ZVKSED, "riscv-zvksed" },
{ HWF_RISCV_ZVKSH, "riscv-zvksh" },
#endif
};
--
2.53.0
More information about the Gcrypt-devel
mailing list