[PATCH 6/7] sm4: add Intel SM4 instructions accelerated AVX512 implementation

Jussi Kivilinna jussi.kivilinna at iki.fi
Sun Jun 28 14:37:40 CEST 2026


* cipher/Makefile.am: Add 'sm4-avx512-amd64.h' and
'sm4-intel-avx512-amd64.S'.
* cipher/sm4-avx512-amd64.h: New, 32-block cipher mode functions moved
here from 'sm4-gfni-avx512-amd64.S'.
* cipher/sm4-gfni-avx512-amd64.S (_gcry_sm4_gfni_avx512_crypt_blk32)
(_gcry_sm4_gfni_avx512_ctr_enc_blk32)
(_gcry_sm4_gfni_avx512_cbc_dec_blk32)
(_gcry_sm4_gfni_avx512_cfb_dec_blk32)
(_gcry_sm4_gfni_avx512_ocb_enc_blk32)
(_gcry_sm4_gfni_avx512_ocb_dec_blk32): Move to 'sm4-avx512-amd64.h'.
(FUNC_NAME, SM4_CRYPT_BLK32): New.
* cipher/sm4-intel-avx512-amd64.S: New.
* cipher/sm4.c (USE_INTEL_SM4_AVX512): New.
(ASM_FUNC_ABI): Define also for Intel SM4 AVX512 implementation.
(SM4_context): Add 'use_intel_sm4_avx512'.
(_gcry_sm4_intel_avx512_ctr_enc_blk32)
(_gcry_sm4_intel_avx512_cbc_dec_blk32)
(_gcry_sm4_intel_avx512_cfb_dec_blk32)
(_gcry_sm4_intel_avx512_ocb_enc_blk32)
(_gcry_sm4_intel_avx512_ocb_dec_blk32)
(_gcry_sm4_intel_avx512_crypt_blk32): New.
(sm4_setkey): Enable Intel SM4 AVX512 implementation if supported by CPU.
(sm4_crypt_blk1_32, _gcry_sm4_ctr_enc, _gcry_sm4_cbc_dec)
(_gcry_sm4_cfb_dec, _gcry_sm4_ocb_crypt) [USE_INTEL_SM4_AVX512]: Add
Intel SM4 AVX512 code path.
* configure.ac (GCRYPT_ASM_CIPHERS) [x86_64]: Add
'sm4-intel-avx512-amd64.lo'.
--

Add a 32-block SM4 implementation using the Intel SM4 instruction set
extension (EVEX/512-bit encoded VSM4RNDS4).  The 32-block cipher mode
code is shared with the GFNI/AVX512 implementation through a new
'sm4-avx512-amd64.h' header; the key schedule and the 16-block and
shorter paths are reused from the AVX2 implementation.  It is used in
preference to the GFNI/AVX512 implementation when available.

Tested with Intel SDE; not yet tested on real hardware.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 cipher/Makefile.am              |   4 +-
 cipher/sm4-avx512-amd64.h       | 620 ++++++++++++++++++++++++++++++++
 cipher/sm4-gfni-avx512-amd64.S  | 593 +-----------------------------
 cipher/sm4-intel-avx512-amd64.S | 174 +++++++++
 cipher/sm4.c                    | 134 ++++++-
 configure.ac                    |   1 +
 6 files changed, 934 insertions(+), 592 deletions(-)
 create mode 100644 cipher/sm4-avx512-amd64.h
 create mode 100644 cipher/sm4-intel-avx512-amd64.S

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 04094a10..8f54ea47 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -137,8 +137,8 @@ EXTRA_libcipher_la_SOURCES = \
 	serpent-avx512-x86.c serpent-armv7-neon.S \
 	simd-common-aarch64.h simd-common-ppc.h simd-common-riscv.h \
 	sm4.c sm4-aesni-avx-amd64.S sm4-aesni-avx2-amd64.S \
-	sm4-avx2-amd64.h \
-	sm4-intel-avx2-amd64.S \
+	sm4-avx2-amd64.h sm4-avx512-amd64.h \
+	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 \
diff --git a/cipher/sm4-avx512-amd64.h b/cipher/sm4-avx512-amd64.h
new file mode 100644
index 00000000..3ee5a4f6
--- /dev/null
+++ b/cipher/sm4-avx512-amd64.h
@@ -0,0 +1,620 @@
+/* sm4-avx512-amd64.h  -  Shared AVX512 32-block cipher mode code for SM4
+ *
+ * Copyright (C) 2022-2023 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/>.
+ */
+
+#ifndef GCRY_SM4_AVX512_AMD64_H
+#define GCRY_SM4_AVX512_AMD64_H
+
+SECTION_RODATA
+.align 64
+
+ELF(.type FUNC_NAME(cipher_mode_consts), at object)
+FUNC_NAME(cipher_mode_consts):
+
+/* CTR mode addition constants */
+
+.Lcounter0123_lo:
+	.quad 0, 0
+	.quad 1, 0
+	.quad 2, 0
+	.quad 3, 0
+
+.Lbige_addb_0_1:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+.Lbige_addb_2_3:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
+.Lbige_addb_4_5:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5
+.Lbige_addb_6_7:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
+.Lbige_addb_8_9:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9
+.Lbige_addb_10_11:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11
+.Lbige_addb_12_13:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13
+.Lbige_addb_14_15:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15
+.Lbige_addb_16:
+	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16
+
+.Lcounter2222_lo:
+	.quad 2, 0
+.Lcounter4444_lo:
+	.quad 4, 0
+.Lcounter8888_lo:
+	.quad 8, 0
+.Lcounter16161616_lo:
+	.quad 16, 0
+.Lcounter1111_hi:
+	.quad 0, 1
+
+.text
+
+.align 16
+.globl FUNC_NAME(crypt_blk32)
+ELF(.type   FUNC_NAME(crypt_blk32), at function;)
+FUNC_NAME(crypt_blk32):
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (32 blocks)
+	 *	%rdx: src (32 blocks)
+	 */
+	CFI_STARTPROC();
+	spec_stop_avx512;
+
+	/* Load input */
+	vmovdqu32 (0 * 64)(%rdx), RA0z;
+	vmovdqu32 (1 * 64)(%rdx), RA1z;
+	vmovdqu32 (2 * 64)(%rdx), RA2z;
+	vmovdqu32 (3 * 64)(%rdx), RA3z;
+	vmovdqu32 (4 * 64)(%rdx), RB0z;
+	vmovdqu32 (5 * 64)(%rdx), RB1z;
+	vmovdqu32 (6 * 64)(%rdx), RB2z;
+	vmovdqu32 (7 * 64)(%rdx), RB3z;
+
+	call SM4_CRYPT_BLK32;
+
+	vmovdqu32 RA0z, (0 * 64)(%rsi);
+	vmovdqu32 RA1z, (1 * 64)(%rsi);
+	vmovdqu32 RA2z, (2 * 64)(%rsi);
+	vmovdqu32 RA3z, (3 * 64)(%rsi);
+	vmovdqu32 RB0z, (4 * 64)(%rsi);
+	vmovdqu32 RB1z, (5 * 64)(%rsi);
+	vmovdqu32 RB2z, (6 * 64)(%rsi);
+	vmovdqu32 RB3z, (7 * 64)(%rsi);
+
+	xorl %eax, %eax;
+	vzeroall;
+
+	ret_spec_stop;
+	CFI_ENDPROC();
+ELF(.size FUNC_NAME(crypt_blk32),.-FUNC_NAME(crypt_blk32);)
+
+.align 16
+.globl FUNC_NAME(ctr_enc_blk32)
+ELF(.type   FUNC_NAME(ctr_enc_blk32), at function;)
+FUNC_NAME(ctr_enc_blk32):
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (32 blocks)
+	 *	%rdx: src (32 blocks)
+	 *	%rcx: iv (big endian, 128bit)
+	 */
+	CFI_STARTPROC();
+	spec_stop_avx512;
+
+	cmpb $(0x100 - 32), 15(%rcx);
+	jbe .Lctr_byteadd32;
+
+	vbroadcasti64x2 .Lbswap128_mask rRIP, RTMP0z;
+	vmovdqa32 .Lcounter0123_lo rRIP, RTMP1z;
+	vbroadcasti64x2 .Lcounter4444_lo rRIP, RTMP2z;
+	vbroadcasti64x2 .Lcounter8888_lo rRIP, RTMP3z;
+	vbroadcasti64x2 .Lcounter16161616_lo rRIP, RTMP4z;
+
+	/* load IV and byteswap */
+	movq 8(%rcx), %r11;
+	bswapq %r11;
+	vbroadcasti64x2 (%rcx), RB3z;
+	vpshufb RTMP0z, RB3z, RB3z;
+
+	/* check need for handling 64-bit overflow and carry */
+	cmpq $(0xffffffffffffffff - 32), %r11;
+	ja .Lhandle_ctr_carry_blk32;
+
+	/* construct IVs */
+	vpaddq RTMP1z, RB3z, RA0z; /* +0:+1:+2:+3 */
+	vpaddq RTMP2z, RA0z, RA1z; /* +4:+5:+6:+7 */
+	vpaddq RTMP3z, RA0z, RA2z; /* +8:+9:+10:+11 */
+	vpaddq RTMP3z, RA1z, RA3z; /* +12:+13:+14:+15 */
+	vpaddq RTMP4z, RA0z, RB0z; /* +16... */
+	vpaddq RTMP4z, RA1z, RB1z; /* +20... */
+	vpaddq RTMP4z, RA2z, RB2z; /* +24... */
+	vpaddq RTMP4z, RA3z, RB3z; /* +28... */
+
+	/* Update counter */
+	leaq 32(%r11), %r11;
+	bswapq %r11;
+	movq %r11, 8(%rcx);
+
+	jmp .Lctr_carry_done_blk32;
+
+.Lhandle_ctr_carry_blk32:
+	vbroadcasti64x2 .Lcounter1111_hi rRIP, RNOTz;
+
+	/* construct IVs */
+	add_le128(RA0z, RB3z, RTMP1z, RNOTz); /* +0:+1:+2:+3 */
+	add_le128(RA1z, RA0z, RTMP2z, RNOTz); /* +4:+5:+6:+7 */
+	add_le128(RA2z, RA0z, RTMP3z, RNOTz); /* +8:+9:+10:+11 */
+	add_le128(RA3z, RA1z, RTMP3z, RNOTz); /* +12:+13:+14:+15 */
+	add_le128(RB0z, RA0z, RTMP4z, RNOTz); /* +16... */
+	add_le128(RB1z, RA1z, RTMP4z, RNOTz); /* +20... */
+	add_le128(RB2z, RA2z, RTMP4z, RNOTz); /* +24... */
+	add_le128(RB3z, RA3z, RTMP4z, RNOTz); /* +28... */
+
+	/* Update counter */
+	addq $32, %r11;
+	movq (%rcx), %r10;
+	bswapq %r10;
+	adcq $0, %r10;
+	bswapq %r11;
+	bswapq %r10;
+	movq %r11, 8(%rcx);
+	movq %r10, (%rcx);
+
+.align 16
+.Lctr_carry_done_blk32:
+	/* Byte-swap IVs. */
+	vpshufb RTMP0z, RA0z, RA0z;
+	vpshufb RTMP0z, RA1z, RA1z;
+	vpshufb RTMP0z, RA2z, RA2z;
+	vpshufb RTMP0z, RA3z, RA3z;
+	vpshufb RTMP0z, RB0z, RB0z;
+	vpshufb RTMP0z, RB1z, RB1z;
+	vpshufb RTMP0z, RB2z, RB2z;
+	vpshufb RTMP0z, RB3z, RB3z;
+
+.align 16
+.Lload_ctr_done32:
+	call SM4_CRYPT_BLK32;
+
+	vpxord (0 * 64)(%rdx), RA0z, RA0z;
+	vpxord (1 * 64)(%rdx), RA1z, RA1z;
+	vpxord (2 * 64)(%rdx), RA2z, RA2z;
+	vpxord (3 * 64)(%rdx), RA3z, RA3z;
+	vpxord (4 * 64)(%rdx), RB0z, RB0z;
+	vpxord (5 * 64)(%rdx), RB1z, RB1z;
+	vpxord (6 * 64)(%rdx), RB2z, RB2z;
+	vpxord (7 * 64)(%rdx), RB3z, RB3z;
+
+	vmovdqu32 RA0z, (0 * 64)(%rsi);
+	vmovdqu32 RA1z, (1 * 64)(%rsi);
+	vmovdqu32 RA2z, (2 * 64)(%rsi);
+	vmovdqu32 RA3z, (3 * 64)(%rsi);
+	vmovdqu32 RB0z, (4 * 64)(%rsi);
+	vmovdqu32 RB1z, (5 * 64)(%rsi);
+	vmovdqu32 RB2z, (6 * 64)(%rsi);
+	vmovdqu32 RB3z, (7 * 64)(%rsi);
+
+	vzeroall;
+	kxorq %k1, %k1, %k1;
+
+	ret_spec_stop;
+
+.align 16
+.Lctr_byteadd_full_ctr_carry32:
+	movq 8(%rcx), %r11;
+	movq (%rcx), %r10;
+	bswapq %r11;
+	bswapq %r10;
+	addq $32, %r11;
+	adcq $0, %r10;
+	bswapq %r11;
+	bswapq %r10;
+	movq %r11, 8(%rcx);
+	movq %r10, (%rcx);
+	jmp .Lctr_byteadd_zmm32;
+.align 16
+.Lctr_byteadd32:
+	vbroadcasti64x2 (%rcx), RA3z;
+	je .Lctr_byteadd_full_ctr_carry32;
+	addb $32, 15(%rcx);
+.Lctr_byteadd_zmm32:
+	vbroadcasti64x2 .Lbige_addb_16 rRIP, RB3z;
+	vpaddb RB3z, RA3z, RB3z;
+	vpaddb .Lbige_addb_0_1 rRIP, RA3z, RA0z;
+	vpaddb .Lbige_addb_4_5 rRIP, RA3z, RA1z;
+	vpaddb .Lbige_addb_8_9 rRIP, RA3z, RA2z;
+	vpaddb .Lbige_addb_12_13 rRIP, RA3z, RA3z;
+	vpaddb .Lbige_addb_0_1 rRIP, RB3z, RB0z;
+	vpaddb .Lbige_addb_4_5 rRIP, RB3z, RB1z;
+	vpaddb .Lbige_addb_8_9 rRIP, RB3z, RB2z;
+	vpaddb .Lbige_addb_12_13 rRIP, RB3z, RB3z;
+
+	jmp .Lload_ctr_done32;
+	CFI_ENDPROC();
+ELF(.size FUNC_NAME(ctr_enc_blk32),.-FUNC_NAME(ctr_enc_blk32);)
+
+.align 16
+.globl FUNC_NAME(cbc_dec_blk32)
+ELF(.type   FUNC_NAME(cbc_dec_blk32), at function;)
+FUNC_NAME(cbc_dec_blk32):
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (32 blocks)
+	 *	%rdx: src (32 blocks)
+	 *	%rcx: iv
+	 */
+	CFI_STARTPROC();
+	spec_stop_avx512;
+
+	vmovdqu32 (0 * 64)(%rdx), RA0z;
+	vmovdqu32 (1 * 64)(%rdx), RA1z;
+	vmovdqu32 (2 * 64)(%rdx), RA2z;
+	vmovdqu32 (3 * 64)(%rdx), RA3z;
+	vmovdqu32 (4 * 64)(%rdx), RB0z;
+	vmovdqu32 (5 * 64)(%rdx), RB1z;
+	vmovdqu32 (6 * 64)(%rdx), RB2z;
+	vmovdqu32 (7 * 64)(%rdx), RB3z;
+
+	call SM4_CRYPT_BLK32;
+
+	vmovdqu (%rcx), RNOTx;
+	vinserti64x2 $1, (0 * 16)(%rdx), RNOT, RNOT;
+	vinserti64x4 $1, (1 * 16)(%rdx), RNOTz, RNOTz;
+	vpxord RNOTz, RA0z, RA0z;
+	vpxord (0 * 64 + 48)(%rdx), RA1z, RA1z;
+	vpxord (1 * 64 + 48)(%rdx), RA2z, RA2z;
+	vpxord (2 * 64 + 48)(%rdx), RA3z, RA3z;
+	vpxord (3 * 64 + 48)(%rdx), RB0z, RB0z;
+	vpxord (4 * 64 + 48)(%rdx), RB1z, RB1z;
+	vpxord (5 * 64 + 48)(%rdx), RB2z, RB2z;
+	vpxord (6 * 64 + 48)(%rdx), RB3z, RB3z;
+	vmovdqu (7 * 64 + 48)(%rdx), RNOTx;
+	vmovdqu RNOTx, (%rcx); /* store new IV */
+
+	vmovdqu32 RA0z, (0 * 64)(%rsi);
+	vmovdqu32 RA1z, (1 * 64)(%rsi);
+	vmovdqu32 RA2z, (2 * 64)(%rsi);
+	vmovdqu32 RA3z, (3 * 64)(%rsi);
+	vmovdqu32 RB0z, (4 * 64)(%rsi);
+	vmovdqu32 RB1z, (5 * 64)(%rsi);
+	vmovdqu32 RB2z, (6 * 64)(%rsi);
+	vmovdqu32 RB3z, (7 * 64)(%rsi);
+
+	vzeroall;
+
+	ret_spec_stop;
+	CFI_ENDPROC();
+ELF(.size FUNC_NAME(cbc_dec_blk32),.-FUNC_NAME(cbc_dec_blk32);)
+
+.align 16
+.globl FUNC_NAME(cfb_dec_blk32)
+ELF(.type   FUNC_NAME(cfb_dec_blk32), at function;)
+FUNC_NAME(cfb_dec_blk32):
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (32 blocks)
+	 *	%rdx: src (32 blocks)
+	 *	%rcx: iv
+	 */
+	CFI_STARTPROC();
+	spec_stop_avx512;
+
+	/* Load input */
+	vmovdqu (%rcx), RA0x;
+	vinserti64x2 $1, (%rdx), RA0, RA0;
+	vinserti64x4 $1, 16(%rdx), RA0z, RA0z;
+	vmovdqu32 (0 * 64 + 48)(%rdx), RA1z;
+	vmovdqu32 (1 * 64 + 48)(%rdx), RA2z;
+	vmovdqu32 (2 * 64 + 48)(%rdx), RA3z;
+	vmovdqu32 (3 * 64 + 48)(%rdx), RB0z;
+	vmovdqu32 (4 * 64 + 48)(%rdx), RB1z;
+	vmovdqu32 (5 * 64 + 48)(%rdx), RB2z;
+	vmovdqu32 (6 * 64 + 48)(%rdx), RB3z;
+
+	/* Update IV */
+	vmovdqu (7 * 64 + 48)(%rdx), RNOTx;
+	vmovdqu RNOTx, (%rcx);
+
+	call SM4_CRYPT_BLK32;
+
+	vpxord (0 * 64)(%rdx), RA0z, RA0z;
+	vpxord (1 * 64)(%rdx), RA1z, RA1z;
+	vpxord (2 * 64)(%rdx), RA2z, RA2z;
+	vpxord (3 * 64)(%rdx), RA3z, RA3z;
+	vpxord (4 * 64)(%rdx), RB0z, RB0z;
+	vpxord (5 * 64)(%rdx), RB1z, RB1z;
+	vpxord (6 * 64)(%rdx), RB2z, RB2z;
+	vpxord (7 * 64)(%rdx), RB3z, RB3z;
+
+	vmovdqu32 RA0z, (0 * 64)(%rsi);
+	vmovdqu32 RA1z, (1 * 64)(%rsi);
+	vmovdqu32 RA2z, (2 * 64)(%rsi);
+	vmovdqu32 RA3z, (3 * 64)(%rsi);
+	vmovdqu32 RB0z, (4 * 64)(%rsi);
+	vmovdqu32 RB1z, (5 * 64)(%rsi);
+	vmovdqu32 RB2z, (6 * 64)(%rsi);
+	vmovdqu32 RB3z, (7 * 64)(%rsi);
+
+	vzeroall;
+
+	ret_spec_stop;
+	CFI_ENDPROC();
+ELF(.size FUNC_NAME(cfb_dec_blk32),.-FUNC_NAME(cfb_dec_blk32);)
+
+.align 16
+.globl FUNC_NAME(ocb_enc_blk32)
+ELF(.type FUNC_NAME(ocb_enc_blk32), at function;)
+FUNC_NAME(ocb_enc_blk32):
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (32 blocks)
+	 *	%rdx: src (32 blocks)
+	 *	%rcx: offset
+	 *	%r8 : checksum
+	 *	%r9 : L pointers (void *L[32])
+	 */
+	CFI_STARTPROC();
+	spec_stop_avx512;
+
+	subq $(5 * 8), %rsp;
+	CFI_ADJUST_CFA_OFFSET(5 * 8);
+
+	movq %r12, (0 * 8)(%rsp);
+	movq %r13, (1 * 8)(%rsp);
+	movq %r14, (2 * 8)(%rsp);
+	movq %r15, (3 * 8)(%rsp);
+	movq %rbx, (4 * 8)(%rsp);
+	CFI_REL_OFFSET(%r12, 0 * 8);
+	CFI_REL_OFFSET(%r13, 1 * 8);
+	CFI_REL_OFFSET(%r14, 2 * 8);
+	CFI_REL_OFFSET(%r15, 3 * 8);
+	CFI_REL_OFFSET(%rbx, 4 * 8);
+
+	vmovdqu (%rcx), RTMP0x;
+
+	/* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+	/* Checksum_i = Checksum_{i-1} xor P_i  */
+	/* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
+
+#define OCB_INPUT(n, l0reg, l1reg, l2reg, l3reg, zreg, zplain) \
+	  vmovdqu32 (n * 64)(%rdx), zplain; \
+	  vpxor (l0reg), RTMP0x, RNOTx; \
+	  vpxor (l1reg), RNOTx, RTMP0x; \
+	  vinserti64x2 $1, RTMP0x, RNOT, RNOT; \
+	  vpxor (l2reg), RTMP0x, RTMP0x; \
+	  vinserti64x2 $2, RTMP0x, RNOTz, RNOTz; \
+	  vpxor (l3reg), RTMP0x, RTMP0x; \
+	  vinserti64x2 $3, RTMP0x, RNOTz, RNOTz; \
+	  vpxord zplain, RNOTz, zreg; \
+	  vmovdqu32 RNOTz, (n * 64)(%rsi);
+
+#define OCB_LOAD_PTRS(n) \
+	  movq ((n * 4 * 8) + (0 * 8))(%r9), %r10; \
+	  movq ((n * 4 * 8) + (1 * 8))(%r9), %r11; \
+	  movq ((n * 4 * 8) + (2 * 8))(%r9), %r12; \
+	  movq ((n * 4 * 8) + (3 * 8))(%r9), %r13; \
+	  movq ((n * 4 * 8) + (4 * 8))(%r9), %r14; \
+	  movq ((n * 4 * 8) + (5 * 8))(%r9), %r15; \
+	  movq ((n * 4 * 8) + (6 * 8))(%r9), %rax; \
+	  movq ((n * 4 * 8) + (7 * 8))(%r9), %rbx;
+
+	OCB_LOAD_PTRS(0);
+	OCB_INPUT(0, %r10, %r11, %r12, %r13, RA0z, RTMP1z);
+	OCB_INPUT(1, %r14, %r15, %rax, %rbx, RA1z, RTMP2z);
+	OCB_LOAD_PTRS(2);
+	OCB_INPUT(2, %r10, %r11, %r12, %r13, RA2z, RTMP3z);
+	vpternlogd $0x96, RTMP1z, RTMP2z, RTMP3z;
+	OCB_INPUT(3, %r14, %r15, %rax, %rbx, RA3z, RTMP4z);
+	OCB_LOAD_PTRS(4);
+	OCB_INPUT(4, %r10, %r11, %r12, %r13, RB0z, RX0z);
+	OCB_INPUT(5, %r14, %r15, %rax, %rbx, RB1z, RX1z);
+	vpternlogd $0x96, RTMP4z, RX0z, RX1z;
+	OCB_LOAD_PTRS(6);
+	OCB_INPUT(6, %r10, %r11, %r12, %r13, RB2z, RTMP4z);
+	OCB_INPUT(7, %r14, %r15, %rax, %rbx, RB3z, RX0z);
+#undef OCB_LOAD_PTRS
+#undef OCB_INPUT
+
+	vpternlogd $0x96, RTMP3z, RTMP4z, RX0z;
+	vpxord RX1z, RX0z, RNOTz;
+	vextracti64x4 $1, RNOTz, RTMP1;
+	vpxor RTMP1, RNOT, RNOT;
+	vextracti128 $1, RNOT, RTMP1x;
+	vpternlogd $0x96, (%r8), RTMP1x, RNOTx;
+
+	movq (0 * 8)(%rsp), %r12;
+	movq (1 * 8)(%rsp), %r13;
+	movq (2 * 8)(%rsp), %r14;
+	movq (3 * 8)(%rsp), %r15;
+	movq (4 * 8)(%rsp), %rbx;
+	CFI_RESTORE(%r12);
+	CFI_RESTORE(%r13);
+	CFI_RESTORE(%r14);
+	CFI_RESTORE(%r15);
+	CFI_RESTORE(%rbx);
+
+	vmovdqu RTMP0x, (%rcx);
+	vmovdqu RNOTx, (%r8);
+
+	call SM4_CRYPT_BLK32;
+
+	addq $(5 * 8), %rsp;
+	CFI_ADJUST_CFA_OFFSET(-5 * 8);
+
+	vpxord (0 * 64)(%rsi), RA0z, RA0z;
+	vpxord (1 * 64)(%rsi), RA1z, RA1z;
+	vpxord (2 * 64)(%rsi), RA2z, RA2z;
+	vpxord (3 * 64)(%rsi), RA3z, RA3z;
+	vpxord (4 * 64)(%rsi), RB0z, RB0z;
+	vpxord (5 * 64)(%rsi), RB1z, RB1z;
+	vpxord (6 * 64)(%rsi), RB2z, RB2z;
+	vpxord (7 * 64)(%rsi), RB3z, RB3z;
+
+	vmovdqu32 RA0z, (0 * 64)(%rsi);
+	vmovdqu32 RA1z, (1 * 64)(%rsi);
+	vmovdqu32 RA2z, (2 * 64)(%rsi);
+	vmovdqu32 RA3z, (3 * 64)(%rsi);
+	vmovdqu32 RB0z, (4 * 64)(%rsi);
+	vmovdqu32 RB1z, (5 * 64)(%rsi);
+	vmovdqu32 RB2z, (6 * 64)(%rsi);
+	vmovdqu32 RB3z, (7 * 64)(%rsi);
+
+	vzeroall;
+
+	ret_spec_stop;
+	CFI_ENDPROC();
+ELF(.size FUNC_NAME(ocb_enc_blk32),.-FUNC_NAME(ocb_enc_blk32);)
+
+.align 16
+.globl FUNC_NAME(ocb_dec_blk32)
+ELF(.type FUNC_NAME(ocb_dec_blk32), at function;)
+FUNC_NAME(ocb_dec_blk32):
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst (32 blocks)
+	 *	%rdx: src (32 blocks)
+	 *	%rcx: offset
+	 *	%r8 : checksum
+	 *	%r9 : L pointers (void *L[32])
+	 */
+	CFI_STARTPROC();
+	spec_stop_avx512;
+
+	subq $(5 * 8), %rsp;
+	CFI_ADJUST_CFA_OFFSET(5 * 8);
+
+	movq %r12, (0 * 8)(%rsp);
+	movq %r13, (1 * 8)(%rsp);
+	movq %r14, (2 * 8)(%rsp);
+	movq %r15, (3 * 8)(%rsp);
+	movq %rbx, (4 * 8)(%rsp);
+	CFI_REL_OFFSET(%r12, 0 * 8);
+	CFI_REL_OFFSET(%r13, 1 * 8);
+	CFI_REL_OFFSET(%r14, 2 * 8);
+	CFI_REL_OFFSET(%r15, 3 * 8);
+	CFI_REL_OFFSET(%rbx, 4 * 8);
+
+	vmovdqu (%rcx), RTMP0x;
+
+	/* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+	/* C_i = Offset_i xor DECIPHER(K, P_i xor Offset_i)  */
+
+#define OCB_INPUT(n, l0reg, l1reg, l2reg, l3reg, zreg) \
+	  vmovdqu32 (n * 64)(%rdx), RTMP1z; \
+	  vpxor (l0reg), RTMP0x, RNOTx; \
+	  vpxor (l1reg), RNOTx, RTMP0x; \
+	  vinserti64x2 $1, RTMP0x, RNOT, RNOT; \
+	  vpxor (l2reg), RTMP0x, RTMP0x; \
+	  vinserti64x2 $2, RTMP0x, RNOTz, RNOTz; \
+	  vpxor (l3reg), RTMP0x, RTMP0x; \
+	  vinserti64x2 $3, RTMP0x, RNOTz, RNOTz; \
+	  vpxord RTMP1z, RNOTz, zreg; \
+	  vmovdqu32 RNOTz, (n * 64)(%rsi);
+
+#define OCB_LOAD_PTRS(n) \
+	  movq ((n * 4 * 8) + (0 * 8))(%r9), %r10; \
+	  movq ((n * 4 * 8) + (1 * 8))(%r9), %r11; \
+	  movq ((n * 4 * 8) + (2 * 8))(%r9), %r12; \
+	  movq ((n * 4 * 8) + (3 * 8))(%r9), %r13; \
+	  movq ((n * 4 * 8) + (4 * 8))(%r9), %r14; \
+	  movq ((n * 4 * 8) + (5 * 8))(%r9), %r15; \
+	  movq ((n * 4 * 8) + (6 * 8))(%r9), %rax; \
+	  movq ((n * 4 * 8) + (7 * 8))(%r9), %rbx;
+
+	OCB_LOAD_PTRS(0);
+	OCB_INPUT(0, %r10, %r11, %r12, %r13, RA0z);
+	OCB_INPUT(1, %r14, %r15, %rax, %rbx, RA1z);
+	OCB_LOAD_PTRS(2);
+	OCB_INPUT(2, %r10, %r11, %r12, %r13, RA2z);
+	OCB_INPUT(3, %r14, %r15, %rax, %rbx, RA3z);
+	OCB_LOAD_PTRS(4);
+	OCB_INPUT(4, %r10, %r11, %r12, %r13, RB0z);
+	OCB_INPUT(5, %r14, %r15, %rax, %rbx, RB1z);
+	OCB_LOAD_PTRS(6);
+	OCB_INPUT(6, %r10, %r11, %r12, %r13, RB2z);
+	OCB_INPUT(7, %r14, %r15, %rax, %rbx, RB3z);
+#undef OCB_LOAD_PTRS
+#undef OCB_INPUT
+
+	movq (0 * 8)(%rsp), %r12;
+	movq (1 * 8)(%rsp), %r13;
+	movq (2 * 8)(%rsp), %r14;
+	movq (3 * 8)(%rsp), %r15;
+	movq (4 * 8)(%rsp), %rbx;
+	CFI_RESTORE(%r12);
+	CFI_RESTORE(%r13);
+	CFI_RESTORE(%r14);
+	CFI_RESTORE(%r15);
+	CFI_RESTORE(%rbx);
+
+	vmovdqu RTMP0x, (%rcx);
+
+	call SM4_CRYPT_BLK32;
+
+	addq $(5 * 8), %rsp;
+	CFI_ADJUST_CFA_OFFSET(-5 * 8);
+
+	vpxord (0 * 64)(%rsi), RA0z, RA0z;
+	vpxord (1 * 64)(%rsi), RA1z, RA1z;
+	vpxord (2 * 64)(%rsi), RA2z, RA2z;
+	vpxord (3 * 64)(%rsi), RA3z, RA3z;
+	vpxord (4 * 64)(%rsi), RB0z, RB0z;
+	vpxord (5 * 64)(%rsi), RB1z, RB1z;
+	vpxord (6 * 64)(%rsi), RB2z, RB2z;
+	vpxord (7 * 64)(%rsi), RB3z, RB3z;
+
+	vmovdqu32 RA0z, (0 * 64)(%rsi);
+	vmovdqu32 RA1z, (1 * 64)(%rsi);
+	vmovdqu32 RA2z, (2 * 64)(%rsi);
+	vmovdqu32 RA3z, (3 * 64)(%rsi);
+	vmovdqu32 RB0z, (4 * 64)(%rsi);
+	vmovdqu32 RB1z, (5 * 64)(%rsi);
+	vmovdqu32 RB2z, (6 * 64)(%rsi);
+	vmovdqu32 RB3z, (7 * 64)(%rsi);
+
+	/* Checksum_i = Checksum_{i-1} xor C_i  */
+	vpternlogd $0x96, RA0z, RA1z, RA2z;
+	vpternlogd $0x96, RA3z, RB0z, RB1z;
+	vpternlogd $0x96, RB2z, RB3z, RA2z;
+	vpxord RA2z, RB1z, RTMP1z;
+
+	vextracti64x4 $1, RTMP1z, RNOT;
+	vpxor RNOT, RTMP1, RTMP1;
+	vextracti128 $1, RTMP1, RNOTx;
+	vpternlogd $0x96, (%r8), RNOTx, RTMP1x;
+	vmovdqu RTMP1x, (%r8);
+
+	vzeroall;
+
+	ret_spec_stop;
+	CFI_ENDPROC();
+ELF(.size FUNC_NAME(ocb_dec_blk32),.-FUNC_NAME(ocb_dec_blk32);)
+
+#endif /* GCRY_SM4_AVX512_AMD64_H */
diff --git a/cipher/sm4-gfni-avx512-amd64.S b/cipher/sm4-gfni-avx512-amd64.S
index 91f6e80b..8bc8bd81 100644
--- a/cipher/sm4-gfni-avx512-amd64.S
+++ b/cipher/sm4-gfni-avx512-amd64.S
@@ -120,7 +120,7 @@ SECTION_RODATA
 	.byte 0x19, 0x8b, 0x6c, 0x1e, 0x51, 0x8e, 0x2d, 0xd7
 	.byte 0x19, 0x8b, 0x6c, 0x1e, 0x51, 0x8e, 0x2d, 0xd7
 
-/* For CTR-mode IV byteswap */
+/* For output IV byteswap */
 .Lbswap128_mask:
 	.byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
 
@@ -128,53 +128,6 @@ SECTION_RODATA
 .Lbswap32_mask:
 	.byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
 
-.Lcounter2222_lo:
-	.quad 2, 0
-.Lcounter4444_lo:
-	.quad 4, 0
-.Lcounter8888_lo:
-	.quad 8, 0
-.Lcounter16161616_lo:
-	.quad 16, 0
-.Lcounter1111_hi:
-	.quad 0, 1
-
-.align 64
-.Lcounter0123_lo:
-	.quad 0, 0
-	.quad 1, 0
-	.quad 2, 0
-	.quad 3, 0
-
-/* CTR byte addition constants */
-.align 64
-.Lbige_addb_0_1:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
-.Lbige_addb_2_3:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
-.Lbige_addb_4_5:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5
-.Lbige_addb_6_7:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
-.Lbige_addb_8_9:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9
-.Lbige_addb_10_11:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11
-.Lbige_addb_12_13:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13
-.Lbige_addb_14_15:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15
-.Lbige_addb_16:
-	.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16
-
 .text
 
 .align 16
@@ -1315,547 +1268,9 @@ __sm4_gfni_crypt_blk32:
 	CFI_ENDPROC();
 ELF(.size __sm4_gfni_crypt_blk32,.-__sm4_gfni_crypt_blk32;)
 
-.align 16
-.globl _gcry_sm4_gfni_avx512_crypt_blk32
-ELF(.type   _gcry_sm4_gfni_avx512_crypt_blk32, at function;)
-_gcry_sm4_gfni_avx512_crypt_blk32:
-	/* input:
-	 *	%rdi: ctx, CTX
-	 *	%rsi: dst (32 blocks)
-	 *	%rdx: src (32 blocks)
-	 */
-	CFI_STARTPROC();
-	spec_stop_avx512;
-
-	/* Load input */
-	vmovdqu32 (0 * 64)(%rdx), RA0z;
-	vmovdqu32 (1 * 64)(%rdx), RA1z;
-	vmovdqu32 (2 * 64)(%rdx), RA2z;
-	vmovdqu32 (3 * 64)(%rdx), RA3z;
-	vmovdqu32 (4 * 64)(%rdx), RB0z;
-	vmovdqu32 (5 * 64)(%rdx), RB1z;
-	vmovdqu32 (6 * 64)(%rdx), RB2z;
-	vmovdqu32 (7 * 64)(%rdx), RB3z;
-
-	call __sm4_gfni_crypt_blk32;
-
-	vmovdqu32 RA0z, (0 * 64)(%rsi);
-	vmovdqu32 RA1z, (1 * 64)(%rsi);
-	vmovdqu32 RA2z, (2 * 64)(%rsi);
-	vmovdqu32 RA3z, (3 * 64)(%rsi);
-	vmovdqu32 RB0z, (4 * 64)(%rsi);
-	vmovdqu32 RB1z, (5 * 64)(%rsi);
-	vmovdqu32 RB2z, (6 * 64)(%rsi);
-	vmovdqu32 RB3z, (7 * 64)(%rsi);
-
-	xorl %eax, %eax;
-	vzeroall;
-
-	ret_spec_stop;
-	CFI_ENDPROC();
-ELF(.size _gcry_sm4_gfni_avx512_crypt_blk32,.-_gcry_sm4_gfni_avx512_crypt_blk32;)
-
-.align 16
-.globl _gcry_sm4_gfni_avx512_ctr_enc_blk32
-ELF(.type   _gcry_sm4_gfni_avx512_ctr_enc_blk32, at function;)
-_gcry_sm4_gfni_avx512_ctr_enc_blk32:
-	/* input:
-	 *	%rdi: ctx, CTX
-	 *	%rsi: dst (32 blocks)
-	 *	%rdx: src (32 blocks)
-	 *	%rcx: iv (big endian, 128bit)
-	 */
-	CFI_STARTPROC();
-	spec_stop_avx512;
-
-	cmpb $(0x100 - 32), 15(%rcx);
-	jbe .Lctr_byteadd32;
-
-	vbroadcasti64x2 .Lbswap128_mask rRIP, RTMP0z;
-	vmovdqa32 .Lcounter0123_lo rRIP, RTMP1z;
-	vbroadcasti64x2 .Lcounter4444_lo rRIP, RTMP2z;
-	vbroadcasti64x2 .Lcounter8888_lo rRIP, RTMP3z;
-	vbroadcasti64x2 .Lcounter16161616_lo rRIP, RTMP4z;
-
-	/* load IV and byteswap */
-	movq 8(%rcx), %r11;
-	bswapq %r11;
-	vbroadcasti64x2 (%rcx), RB3z;
-	vpshufb RTMP0z, RB3z, RB3z;
-
-	/* check need for handling 64-bit overflow and carry */
-	cmpq $(0xffffffffffffffff - 32), %r11;
-	ja .Lhandle_ctr_carry_blk32;
-
-	/* construct IVs */
-	vpaddq RTMP1z, RB3z, RA0z; /* +0:+1:+2:+3 */
-	vpaddq RTMP2z, RA0z, RA1z; /* +4:+5:+6:+7 */
-	vpaddq RTMP3z, RA0z, RA2z; /* +8:+9:+10:+11 */
-	vpaddq RTMP3z, RA1z, RA3z; /* +12:+13:+14:+15 */
-	vpaddq RTMP4z, RA0z, RB0z; /* +16... */
-	vpaddq RTMP4z, RA1z, RB1z; /* +20... */
-	vpaddq RTMP4z, RA2z, RB2z; /* +24... */
-	vpaddq RTMP4z, RA3z, RB3z; /* +28... */
-
-	/* Update counter */
-	leaq 32(%r11), %r11;
-	bswapq %r11;
-	movq %r11, 8(%rcx);
-
-	jmp .Lctr_carry_done_blk32;
-
-.Lhandle_ctr_carry_blk32:
-	vbroadcasti64x2 .Lcounter1111_hi rRIP, RNOTz;
-
-	/* construct IVs */
-	add_le128(RA0z, RB3z, RTMP1z, RNOTz); /* +0:+1:+2:+3 */
-	add_le128(RA1z, RA0z, RTMP2z, RNOTz); /* +4:+5:+6:+7 */
-	add_le128(RA2z, RA0z, RTMP3z, RNOTz); /* +8:+9:+10:+11 */
-	add_le128(RA3z, RA1z, RTMP3z, RNOTz); /* +12:+13:+14:+15 */
-	add_le128(RB0z, RA0z, RTMP4z, RNOTz); /* +16... */
-	add_le128(RB1z, RA1z, RTMP4z, RNOTz); /* +20... */
-	add_le128(RB2z, RA2z, RTMP4z, RNOTz); /* +24... */
-	add_le128(RB3z, RA3z, RTMP4z, RNOTz); /* +28... */
-
-	/* Update counter */
-	addq $32, %r11;
-	movq (%rcx), %r10;
-	bswapq %r10;
-	adcq $0, %r10;
-	bswapq %r11;
-	bswapq %r10;
-	movq %r11, 8(%rcx);
-	movq %r10, (%rcx);
-
-.align 16
-.Lctr_carry_done_blk32:
-	/* Byte-swap IVs. */
-	vpshufb RTMP0z, RA0z, RA0z;
-	vpshufb RTMP0z, RA1z, RA1z;
-	vpshufb RTMP0z, RA2z, RA2z;
-	vpshufb RTMP0z, RA3z, RA3z;
-	vpshufb RTMP0z, RB0z, RB0z;
-	vpshufb RTMP0z, RB1z, RB1z;
-	vpshufb RTMP0z, RB2z, RB2z;
-	vpshufb RTMP0z, RB3z, RB3z;
-
-.align 16
-.Lload_ctr_done32:
-	call __sm4_gfni_crypt_blk32;
-
-	vpxord (0 * 64)(%rdx), RA0z, RA0z;
-	vpxord (1 * 64)(%rdx), RA1z, RA1z;
-	vpxord (2 * 64)(%rdx), RA2z, RA2z;
-	vpxord (3 * 64)(%rdx), RA3z, RA3z;
-	vpxord (4 * 64)(%rdx), RB0z, RB0z;
-	vpxord (5 * 64)(%rdx), RB1z, RB1z;
-	vpxord (6 * 64)(%rdx), RB2z, RB2z;
-	vpxord (7 * 64)(%rdx), RB3z, RB3z;
-
-	vmovdqu32 RA0z, (0 * 64)(%rsi);
-	vmovdqu32 RA1z, (1 * 64)(%rsi);
-	vmovdqu32 RA2z, (2 * 64)(%rsi);
-	vmovdqu32 RA3z, (3 * 64)(%rsi);
-	vmovdqu32 RB0z, (4 * 64)(%rsi);
-	vmovdqu32 RB1z, (5 * 64)(%rsi);
-	vmovdqu32 RB2z, (6 * 64)(%rsi);
-	vmovdqu32 RB3z, (7 * 64)(%rsi);
-
-	vzeroall;
-	kxorq %k1, %k1, %k1;
-
-	ret_spec_stop;
-
-.align 16
-.Lctr_byteadd_full_ctr_carry32:
-	movq 8(%rcx), %r11;
-	movq (%rcx), %r10;
-	bswapq %r11;
-	bswapq %r10;
-	addq $32, %r11;
-	adcq $0, %r10;
-	bswapq %r11;
-	bswapq %r10;
-	movq %r11, 8(%rcx);
-	movq %r10, (%rcx);
-	jmp .Lctr_byteadd_zmm32;
-.align 16
-.Lctr_byteadd32:
-	vbroadcasti64x2 (%rcx), RA3z;
-	je .Lctr_byteadd_full_ctr_carry32;
-	addb $32, 15(%rcx);
-.Lctr_byteadd_zmm32:
-	vbroadcasti64x2 .Lbige_addb_16 rRIP, RB3z;
-	vpaddb RB3z, RA3z, RB3z;
-	vpaddb .Lbige_addb_0_1 rRIP, RA3z, RA0z;
-	vpaddb .Lbige_addb_4_5 rRIP, RA3z, RA1z;
-	vpaddb .Lbige_addb_8_9 rRIP, RA3z, RA2z;
-	vpaddb .Lbige_addb_12_13 rRIP, RA3z, RA3z;
-	vpaddb .Lbige_addb_0_1 rRIP, RB3z, RB0z;
-	vpaddb .Lbige_addb_4_5 rRIP, RB3z, RB1z;
-	vpaddb .Lbige_addb_8_9 rRIP, RB3z, RB2z;
-	vpaddb .Lbige_addb_12_13 rRIP, RB3z, RB3z;
-
-	jmp .Lload_ctr_done32;
-	CFI_ENDPROC();
-ELF(.size _gcry_sm4_gfni_avx512_ctr_enc_blk32,.-_gcry_sm4_gfni_avx512_ctr_enc_blk32;)
-
-.align 16
-.globl _gcry_sm4_gfni_avx512_cbc_dec_blk32
-ELF(.type   _gcry_sm4_gfni_avx512_cbc_dec_blk32, at function;)
-_gcry_sm4_gfni_avx512_cbc_dec_blk32:
-	/* input:
-	 *	%rdi: ctx, CTX
-	 *	%rsi: dst (32 blocks)
-	 *	%rdx: src (32 blocks)
-	 *	%rcx: iv
-	 */
-	CFI_STARTPROC();
-	spec_stop_avx512;
-
-	vmovdqu32 (0 * 64)(%rdx), RA0z;
-	vmovdqu32 (1 * 64)(%rdx), RA1z;
-	vmovdqu32 (2 * 64)(%rdx), RA2z;
-	vmovdqu32 (3 * 64)(%rdx), RA3z;
-	vmovdqu32 (4 * 64)(%rdx), RB0z;
-	vmovdqu32 (5 * 64)(%rdx), RB1z;
-	vmovdqu32 (6 * 64)(%rdx), RB2z;
-	vmovdqu32 (7 * 64)(%rdx), RB3z;
-
-	call __sm4_gfni_crypt_blk32;
-
-	vmovdqu (%rcx), RNOTx;
-	vinserti64x2 $1, (0 * 16)(%rdx), RNOT, RNOT;
-	vinserti64x4 $1, (1 * 16)(%rdx), RNOTz, RNOTz;
-	vpxord RNOTz, RA0z, RA0z;
-	vpxord (0 * 64 + 48)(%rdx), RA1z, RA1z;
-	vpxord (1 * 64 + 48)(%rdx), RA2z, RA2z;
-	vpxord (2 * 64 + 48)(%rdx), RA3z, RA3z;
-	vpxord (3 * 64 + 48)(%rdx), RB0z, RB0z;
-	vpxord (4 * 64 + 48)(%rdx), RB1z, RB1z;
-	vpxord (5 * 64 + 48)(%rdx), RB2z, RB2z;
-	vpxord (6 * 64 + 48)(%rdx), RB3z, RB3z;
-	vmovdqu (7 * 64 + 48)(%rdx), RNOTx;
-	vmovdqu RNOTx, (%rcx); /* store new IV */
-
-	vmovdqu32 RA0z, (0 * 64)(%rsi);
-	vmovdqu32 RA1z, (1 * 64)(%rsi);
-	vmovdqu32 RA2z, (2 * 64)(%rsi);
-	vmovdqu32 RA3z, (3 * 64)(%rsi);
-	vmovdqu32 RB0z, (4 * 64)(%rsi);
-	vmovdqu32 RB1z, (5 * 64)(%rsi);
-	vmovdqu32 RB2z, (6 * 64)(%rsi);
-	vmovdqu32 RB3z, (7 * 64)(%rsi);
-
-	vzeroall;
-
-	ret_spec_stop;
-	CFI_ENDPROC();
-ELF(.size _gcry_sm4_gfni_avx512_cbc_dec_blk32,.-_gcry_sm4_gfni_avx512_cbc_dec_blk32;)
-
-.align 16
-.globl _gcry_sm4_gfni_avx512_cfb_dec_blk32
-ELF(.type   _gcry_sm4_gfni_avx512_cfb_dec_blk32, at function;)
-_gcry_sm4_gfni_avx512_cfb_dec_blk32:
-	/* input:
-	 *	%rdi: ctx, CTX
-	 *	%rsi: dst (32 blocks)
-	 *	%rdx: src (32 blocks)
-	 *	%rcx: iv
-	 */
-	CFI_STARTPROC();
-	spec_stop_avx512;
-
-	/* Load input */
-	vmovdqu (%rcx), RA0x;
-	vinserti64x2 $1, (%rdx), RA0, RA0;
-	vinserti64x4 $1, 16(%rdx), RA0z, RA0z;
-	vmovdqu32 (0 * 64 + 48)(%rdx), RA1z;
-	vmovdqu32 (1 * 64 + 48)(%rdx), RA2z;
-	vmovdqu32 (2 * 64 + 48)(%rdx), RA3z;
-	vmovdqu32 (3 * 64 + 48)(%rdx), RB0z;
-	vmovdqu32 (4 * 64 + 48)(%rdx), RB1z;
-	vmovdqu32 (5 * 64 + 48)(%rdx), RB2z;
-	vmovdqu32 (6 * 64 + 48)(%rdx), RB3z;
-
-	/* Update IV */
-	vmovdqu (7 * 64 + 48)(%rdx), RNOTx;
-	vmovdqu RNOTx, (%rcx);
-
-	call __sm4_gfni_crypt_blk32;
-
-	vpxord (0 * 64)(%rdx), RA0z, RA0z;
-	vpxord (1 * 64)(%rdx), RA1z, RA1z;
-	vpxord (2 * 64)(%rdx), RA2z, RA2z;
-	vpxord (3 * 64)(%rdx), RA3z, RA3z;
-	vpxord (4 * 64)(%rdx), RB0z, RB0z;
-	vpxord (5 * 64)(%rdx), RB1z, RB1z;
-	vpxord (6 * 64)(%rdx), RB2z, RB2z;
-	vpxord (7 * 64)(%rdx), RB3z, RB3z;
-
-	vmovdqu32 RA0z, (0 * 64)(%rsi);
-	vmovdqu32 RA1z, (1 * 64)(%rsi);
-	vmovdqu32 RA2z, (2 * 64)(%rsi);
-	vmovdqu32 RA3z, (3 * 64)(%rsi);
-	vmovdqu32 RB0z, (4 * 64)(%rsi);
-	vmovdqu32 RB1z, (5 * 64)(%rsi);
-	vmovdqu32 RB2z, (6 * 64)(%rsi);
-	vmovdqu32 RB3z, (7 * 64)(%rsi);
-
-	vzeroall;
-
-	ret_spec_stop;
-	CFI_ENDPROC();
-ELF(.size _gcry_sm4_gfni_avx512_cfb_dec_blk32,.-_gcry_sm4_gfni_avx512_cfb_dec_blk32;)
-
-.align 16
-.globl _gcry_sm4_gfni_avx512_ocb_enc_blk32
-ELF(.type _gcry_sm4_gfni_avx512_ocb_enc_blk32, at function;)
-_gcry_sm4_gfni_avx512_ocb_enc_blk32:
-	/* input:
-	 *	%rdi: ctx, CTX
-	 *	%rsi: dst (32 blocks)
-	 *	%rdx: src (32 blocks)
-	 *	%rcx: offset
-	 *	%r8 : checksum
-	 *	%r9 : L pointers (void *L[32])
-	 */
-	CFI_STARTPROC();
-	spec_stop_avx512;
-
-	subq $(5 * 8), %rsp;
-	CFI_ADJUST_CFA_OFFSET(5 * 8);
-
-	movq %r12, (0 * 8)(%rsp);
-	movq %r13, (1 * 8)(%rsp);
-	movq %r14, (2 * 8)(%rsp);
-	movq %r15, (3 * 8)(%rsp);
-	movq %rbx, (4 * 8)(%rsp);
-	CFI_REL_OFFSET(%r12, 0 * 8);
-	CFI_REL_OFFSET(%r13, 1 * 8);
-	CFI_REL_OFFSET(%r14, 2 * 8);
-	CFI_REL_OFFSET(%r15, 3 * 8);
-	CFI_REL_OFFSET(%rbx, 4 * 8);
-
-	vmovdqu (%rcx), RTMP0x;
-
-	/* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
-	/* Checksum_i = Checksum_{i-1} xor P_i  */
-	/* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
-
-#define OCB_INPUT(n, l0reg, l1reg, l2reg, l3reg, zreg, zplain) \
-	  vmovdqu32 (n * 64)(%rdx), zplain; \
-	  vpxor (l0reg), RTMP0x, RNOTx; \
-	  vpxor (l1reg), RNOTx, RTMP0x; \
-	  vinserti64x2 $1, RTMP0x, RNOT, RNOT; \
-	  vpxor (l2reg), RTMP0x, RTMP0x; \
-	  vinserti64x2 $2, RTMP0x, RNOTz, RNOTz; \
-	  vpxor (l3reg), RTMP0x, RTMP0x; \
-	  vinserti64x2 $3, RTMP0x, RNOTz, RNOTz; \
-	  vpxord zplain, RNOTz, zreg; \
-	  vmovdqu32 RNOTz, (n * 64)(%rsi);
-
-#define OCB_LOAD_PTRS(n) \
-	  movq ((n * 4 * 8) + (0 * 8))(%r9), %r10; \
-	  movq ((n * 4 * 8) + (1 * 8))(%r9), %r11; \
-	  movq ((n * 4 * 8) + (2 * 8))(%r9), %r12; \
-	  movq ((n * 4 * 8) + (3 * 8))(%r9), %r13; \
-	  movq ((n * 4 * 8) + (4 * 8))(%r9), %r14; \
-	  movq ((n * 4 * 8) + (5 * 8))(%r9), %r15; \
-	  movq ((n * 4 * 8) + (6 * 8))(%r9), %rax; \
-	  movq ((n * 4 * 8) + (7 * 8))(%r9), %rbx;
-
-	OCB_LOAD_PTRS(0);
-	OCB_INPUT(0, %r10, %r11, %r12, %r13, RA0z, RTMP1z);
-	OCB_INPUT(1, %r14, %r15, %rax, %rbx, RA1z, RTMP2z);
-	OCB_LOAD_PTRS(2);
-	OCB_INPUT(2, %r10, %r11, %r12, %r13, RA2z, RTMP3z);
-	vpternlogd $0x96, RTMP1z, RTMP2z, RTMP3z;
-	OCB_INPUT(3, %r14, %r15, %rax, %rbx, RA3z, RTMP4z);
-	OCB_LOAD_PTRS(4);
-	OCB_INPUT(4, %r10, %r11, %r12, %r13, RB0z, RX0z);
-	OCB_INPUT(5, %r14, %r15, %rax, %rbx, RB1z, RX1z);
-	vpternlogd $0x96, RTMP4z, RX0z, RX1z;
-	OCB_LOAD_PTRS(6);
-	OCB_INPUT(6, %r10, %r11, %r12, %r13, RB2z, RTMP4z);
-	OCB_INPUT(7, %r14, %r15, %rax, %rbx, RB3z, RX0z);
-#undef OCB_LOAD_PTRS
-#undef OCB_INPUT
-
-	vpternlogd $0x96, RTMP3z, RTMP4z, RX0z;
-	vpxord RX1z, RX0z, RNOTz;
-	vextracti64x4 $1, RNOTz, RTMP1;
-	vpxor RTMP1, RNOT, RNOT;
-	vextracti128 $1, RNOT, RTMP1x;
-	vpternlogd $0x96, (%r8), RTMP1x, RNOTx;
-
-	movq (0 * 8)(%rsp), %r12;
-	movq (1 * 8)(%rsp), %r13;
-	movq (2 * 8)(%rsp), %r14;
-	movq (3 * 8)(%rsp), %r15;
-	movq (4 * 8)(%rsp), %rbx;
-	CFI_RESTORE(%r12);
-	CFI_RESTORE(%r13);
-	CFI_RESTORE(%r14);
-	CFI_RESTORE(%r15);
-	CFI_RESTORE(%rbx);
-
-	vmovdqu RTMP0x, (%rcx);
-	vmovdqu RNOTx, (%r8);
-
-	call __sm4_gfni_crypt_blk32;
-
-	addq $(5 * 8), %rsp;
-	CFI_ADJUST_CFA_OFFSET(-5 * 8);
-
-	vpxord (0 * 64)(%rsi), RA0z, RA0z;
-	vpxord (1 * 64)(%rsi), RA1z, RA1z;
-	vpxord (2 * 64)(%rsi), RA2z, RA2z;
-	vpxord (3 * 64)(%rsi), RA3z, RA3z;
-	vpxord (4 * 64)(%rsi), RB0z, RB0z;
-	vpxord (5 * 64)(%rsi), RB1z, RB1z;
-	vpxord (6 * 64)(%rsi), RB2z, RB2z;
-	vpxord (7 * 64)(%rsi), RB3z, RB3z;
-
-	vmovdqu32 RA0z, (0 * 64)(%rsi);
-	vmovdqu32 RA1z, (1 * 64)(%rsi);
-	vmovdqu32 RA2z, (2 * 64)(%rsi);
-	vmovdqu32 RA3z, (3 * 64)(%rsi);
-	vmovdqu32 RB0z, (4 * 64)(%rsi);
-	vmovdqu32 RB1z, (5 * 64)(%rsi);
-	vmovdqu32 RB2z, (6 * 64)(%rsi);
-	vmovdqu32 RB3z, (7 * 64)(%rsi);
-
-	vzeroall;
-
-	ret_spec_stop;
-	CFI_ENDPROC();
-ELF(.size _gcry_sm4_gfni_avx512_ocb_enc_blk32,.-_gcry_sm4_gfni_avx512_ocb_enc_blk32;)
-
-.align 16
-.globl _gcry_sm4_gfni_avx512_ocb_dec_blk32
-ELF(.type _gcry_sm4_gfni_avx512_ocb_dec_blk32, at function;)
-_gcry_sm4_gfni_avx512_ocb_dec_blk32:
-	/* input:
-	 *	%rdi: ctx, CTX
-	 *	%rsi: dst (32 blocks)
-	 *	%rdx: src (32 blocks)
-	 *	%rcx: offset
-	 *	%r8 : checksum
-	 *	%r9 : L pointers (void *L[32])
-	 */
-	CFI_STARTPROC();
-	spec_stop_avx512;
-
-	subq $(5 * 8), %rsp;
-	CFI_ADJUST_CFA_OFFSET(5 * 8);
-
-	movq %r12, (0 * 8)(%rsp);
-	movq %r13, (1 * 8)(%rsp);
-	movq %r14, (2 * 8)(%rsp);
-	movq %r15, (3 * 8)(%rsp);
-	movq %rbx, (4 * 8)(%rsp);
-	CFI_REL_OFFSET(%r12, 0 * 8);
-	CFI_REL_OFFSET(%r13, 1 * 8);
-	CFI_REL_OFFSET(%r14, 2 * 8);
-	CFI_REL_OFFSET(%r15, 3 * 8);
-	CFI_REL_OFFSET(%rbx, 4 * 8);
-
-	vmovdqu (%rcx), RTMP0x;
-
-	/* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
-	/* C_i = Offset_i xor DECIPHER(K, P_i xor Offset_i)  */
-
-#define OCB_INPUT(n, l0reg, l1reg, l2reg, l3reg, zreg) \
-	  vmovdqu32 (n * 64)(%rdx), RTMP1z; \
-	  vpxor (l0reg), RTMP0x, RNOTx; \
-	  vpxor (l1reg), RNOTx, RTMP0x; \
-	  vinserti64x2 $1, RTMP0x, RNOT, RNOT; \
-	  vpxor (l2reg), RTMP0x, RTMP0x; \
-	  vinserti64x2 $2, RTMP0x, RNOTz, RNOTz; \
-	  vpxor (l3reg), RTMP0x, RTMP0x; \
-	  vinserti64x2 $3, RTMP0x, RNOTz, RNOTz; \
-	  vpxord RTMP1z, RNOTz, zreg; \
-	  vmovdqu32 RNOTz, (n * 64)(%rsi);
-
-#define OCB_LOAD_PTRS(n) \
-	  movq ((n * 4 * 8) + (0 * 8))(%r9), %r10; \
-	  movq ((n * 4 * 8) + (1 * 8))(%r9), %r11; \
-	  movq ((n * 4 * 8) + (2 * 8))(%r9), %r12; \
-	  movq ((n * 4 * 8) + (3 * 8))(%r9), %r13; \
-	  movq ((n * 4 * 8) + (4 * 8))(%r9), %r14; \
-	  movq ((n * 4 * 8) + (5 * 8))(%r9), %r15; \
-	  movq ((n * 4 * 8) + (6 * 8))(%r9), %rax; \
-	  movq ((n * 4 * 8) + (7 * 8))(%r9), %rbx;
-
-	OCB_LOAD_PTRS(0);
-	OCB_INPUT(0, %r10, %r11, %r12, %r13, RA0z);
-	OCB_INPUT(1, %r14, %r15, %rax, %rbx, RA1z);
-	OCB_LOAD_PTRS(2);
-	OCB_INPUT(2, %r10, %r11, %r12, %r13, RA2z);
-	OCB_INPUT(3, %r14, %r15, %rax, %rbx, RA3z);
-	OCB_LOAD_PTRS(4);
-	OCB_INPUT(4, %r10, %r11, %r12, %r13, RB0z);
-	OCB_INPUT(5, %r14, %r15, %rax, %rbx, RB1z);
-	OCB_LOAD_PTRS(6);
-	OCB_INPUT(6, %r10, %r11, %r12, %r13, RB2z);
-	OCB_INPUT(7, %r14, %r15, %rax, %rbx, RB3z);
-#undef OCB_LOAD_PTRS
-#undef OCB_INPUT
-
-	movq (0 * 8)(%rsp), %r12;
-	movq (1 * 8)(%rsp), %r13;
-	movq (2 * 8)(%rsp), %r14;
-	movq (3 * 8)(%rsp), %r15;
-	movq (4 * 8)(%rsp), %rbx;
-	CFI_RESTORE(%r12);
-	CFI_RESTORE(%r13);
-	CFI_RESTORE(%r14);
-	CFI_RESTORE(%r15);
-	CFI_RESTORE(%rbx);
-
-	vmovdqu RTMP0x, (%rcx);
-
-	call __sm4_gfni_crypt_blk32;
-
-	addq $(5 * 8), %rsp;
-	CFI_ADJUST_CFA_OFFSET(-5 * 8);
-
-	vpxord (0 * 64)(%rsi), RA0z, RA0z;
-	vpxord (1 * 64)(%rsi), RA1z, RA1z;
-	vpxord (2 * 64)(%rsi), RA2z, RA2z;
-	vpxord (3 * 64)(%rsi), RA3z, RA3z;
-	vpxord (4 * 64)(%rsi), RB0z, RB0z;
-	vpxord (5 * 64)(%rsi), RB1z, RB1z;
-	vpxord (6 * 64)(%rsi), RB2z, RB2z;
-	vpxord (7 * 64)(%rsi), RB3z, RB3z;
-
-	vmovdqu32 RA0z, (0 * 64)(%rsi);
-	vmovdqu32 RA1z, (1 * 64)(%rsi);
-	vmovdqu32 RA2z, (2 * 64)(%rsi);
-	vmovdqu32 RA3z, (3 * 64)(%rsi);
-	vmovdqu32 RB0z, (4 * 64)(%rsi);
-	vmovdqu32 RB1z, (5 * 64)(%rsi);
-	vmovdqu32 RB2z, (6 * 64)(%rsi);
-	vmovdqu32 RB3z, (7 * 64)(%rsi);
-
-	/* Checksum_i = Checksum_{i-1} xor C_i  */
-	vpternlogd $0x96, RA0z, RA1z, RA2z;
-	vpternlogd $0x96, RA3z, RB0z, RB1z;
-	vpternlogd $0x96, RB2z, RB3z, RA2z;
-	vpxord RA2z, RB1z, RTMP1z;
-
-	vextracti64x4 $1, RTMP1z, RNOT;
-	vpxor RNOT, RTMP1, RTMP1;
-	vextracti128 $1, RTMP1, RNOTx;
-	vpternlogd $0x96, (%r8), RNOTx, RTMP1x;
-	vmovdqu RTMP1x, (%r8);
-
-	vzeroall;
-
-	ret_spec_stop;
-	CFI_ENDPROC();
-ELF(.size _gcry_sm4_gfni_avx512_ocb_dec_blk32,.-_gcry_sm4_gfni_avx512_ocb_dec_blk32;)
+#define FUNC_NAME(func) _gcry_sm4_gfni_avx512_ ## func
+#define SM4_CRYPT_BLK32 __sm4_gfni_crypt_blk32
+#include "sm4-avx512-amd64.h"
 
 #endif /*defined(ENABLE_GFNI_SUPPORT) && defined(ENABLE_AVX512_SUPPORT)*/
 #endif /*__x86_64*/
diff --git a/cipher/sm4-intel-avx512-amd64.S b/cipher/sm4-intel-avx512-amd64.S
new file mode 100644
index 00000000..a4963db0
--- /dev/null
+++ b/cipher/sm4-intel-avx512-amd64.S
@@ -0,0 +1,174 @@
+/* sm4-intel-avx512-amd64.S  -  Intel SM4 instructions AVX512 SM4 cipher
+ *
+ * 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>
+
+#ifdef __x86_64
+#if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
+     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \
+    defined(ENABLE_AVX512_SUPPORT) && defined(HAVE_GCC_INLINE_ASM_SM4)
+
+#include "asm-common-amd64.h"
+
+/* vector registers */
+#define RA0          %ymm0
+#define RA1          %ymm1
+#define RA2          %ymm2
+#define RA3          %ymm3
+#define RA0x         %xmm0
+#define RA1x         %xmm1
+#define RA2x         %xmm2
+#define RA3x         %xmm3
+#define RA0z         %zmm0
+#define RA1z         %zmm1
+#define RA2z         %zmm2
+#define RA3z         %zmm3
+
+#define RTMP0        %ymm4
+#define RTMP1        %ymm5
+#define RTMP2        %ymm6
+#define RTMP3        %ymm7
+#define RTMP4        %ymm8
+#define RTMP0x       %xmm4
+#define RTMP1x       %xmm5
+#define RTMP2x       %xmm6
+#define RTMP3x       %xmm7
+#define RTMP4x       %xmm8
+#define RTMP0z       %zmm4
+#define RTMP1z       %zmm5
+#define RTMP2z       %zmm6
+#define RTMP3z       %zmm7
+#define RTMP4z       %zmm8
+
+#define RB0          %ymm9
+#define RB1          %ymm10
+#define RB2          %ymm11
+#define RB3          %ymm12
+#define RB0x         %xmm9
+#define RB1x         %xmm10
+#define RB2x         %xmm11
+#define RB3x         %xmm12
+#define RB0z         %zmm9
+#define RB1z         %zmm10
+#define RB2z         %zmm11
+#define RB3z         %zmm12
+
+#define RX0          %ymm13
+#define RX1          %ymm14
+#define RX0x         %xmm13
+#define RX1x         %xmm14
+#define RX0z         %zmm13
+#define RX1z         %zmm14
+
+#define RNOT         %ymm15
+#define RNOTx        %xmm15
+#define RNOTz        %zmm15
+
+SECTION_RODATA
+.align 32
+
+ELF(.type _sm4_intel_avx512_consts, at object)
+_sm4_intel_avx512_consts:
+
+/* For output word byte-swap */
+.Lbswap128_mask:
+	.byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+/* For input word byte-swap */
+.Lbswap32_mask:
+	.byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+
+.text
+
+/**********************************************************************
+  32-way SM4 with Intel SM4 instructions
+ **********************************************************************/
+
+.align 16
+ELF(.type   __sm4_intel_crypt_blk32, at function;)
+__sm4_intel_crypt_blk32:
+	/* input:
+	 *	%rdi: round key array, CTX
+	 *	RA0z, RA1z, RA2z, RA3z, RB0z, RB1z, RB2z, RB3z: 32 parallel
+	 *						plaintext blocks
+	 * output:
+	 *	RA0z, RA1z, RA2z, RA3z, RB0z, RB1z, RB2z, RB3z: 32 parallel
+	 *						ciphertext blocks
+	 */
+	CFI_STARTPROC();
+
+	vbroadcasti32x4 .Lbswap32_mask rRIP, RTMP0z;
+	vpshufb RTMP0z, RA0z, RA0z;
+	vpshufb RTMP0z, RA1z, RA1z;
+	vpshufb RTMP0z, RA2z, RA2z;
+	vpshufb RTMP0z, RA3z, RA3z;
+	vpshufb RTMP0z, RB0z, RB0z;
+	vpshufb RTMP0z, RB1z, RB1z;
+	vpshufb RTMP0z, RB2z, RB2z;
+	vpshufb RTMP0z, RB3z, RB3z;
+
+#define ROUND4(rkoff) \
+	vbroadcasti32x4 (rkoff)(%rdi), RTMP1z; \
+	vsm4rnds4 RTMP1z, RA0z, RA0z; \
+	vsm4rnds4 RTMP1z, RA1z, RA1z; \
+	vsm4rnds4 RTMP1z, RA2z, RA2z; \
+	vsm4rnds4 RTMP1z, RA3z, RA3z; \
+	vsm4rnds4 RTMP1z, RB0z, RB0z; \
+	vsm4rnds4 RTMP1z, RB1z, RB1z; \
+	vsm4rnds4 RTMP1z, RB2z, RB2z; \
+	vsm4rnds4 RTMP1z, RB3z, RB3z;
+
+	ROUND4(0 * 16);
+	ROUND4(1 * 16);
+	ROUND4(2 * 16);
+	ROUND4(3 * 16);
+	ROUND4(4 * 16);
+	ROUND4(5 * 16);
+	ROUND4(6 * 16);
+	ROUND4(7 * 16);
+
+#undef ROUND4
+
+	vbroadcasti32x4 .Lbswap128_mask rRIP, RTMP0z;
+	vpshufb RTMP0z, RA0z, RA0z;
+	vpshufb RTMP0z, RA1z, RA1z;
+	vpshufb RTMP0z, RA2z, RA2z;
+	vpshufb RTMP0z, RA3z, RA3z;
+	vpshufb RTMP0z, RB0z, RB0z;
+	vpshufb RTMP0z, RB1z, RB1z;
+	vpshufb RTMP0z, RB2z, RB2z;
+	vpshufb RTMP0z, RB3z, RB3z;
+
+	ret_spec_stop;
+	CFI_ENDPROC();
+ELF(.size __sm4_intel_crypt_blk32,.-__sm4_intel_crypt_blk32;)
+
+#define add_le128(out, in, lo_counter, hi_counter1) \
+	vpaddq lo_counter, in, out; \
+	vpcmpuq $1, lo_counter, out, %k1; \
+	kaddb %k1, %k1, %k1; \
+	vpaddq hi_counter1, out, out{%k1};
+
+#define FUNC_NAME(func) _gcry_sm4_intel_avx512_ ## func
+#define SM4_CRYPT_BLK32 __sm4_intel_crypt_blk32
+#include "sm4-avx512-amd64.h"
+
+#endif /*defined(ENABLE_AVX512_SUPPORT) && defined(HAVE_GCC_INLINE_ASM_SM4)*/
+#endif /*__x86_64*/
diff --git a/cipher/sm4.c b/cipher/sm4.c
index e397e452..37e1a6c3 100644
--- a/cipher/sm4.c
+++ b/cipher/sm4.c
@@ -84,12 +84,22 @@
 # endif
 #endif
 
+/* USE_INTEL_SM4_AVX512 indicates whether to compile with Intel SM4
+ * instructions (VSM4RNDS4) based AVX512 code. */
+#undef USE_INTEL_SM4_AVX512
+#if defined(ENABLE_AVX512_SUPPORT) && defined(HAVE_GCC_INLINE_ASM_SM4)
+# if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
+     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
+#  define USE_INTEL_SM4_AVX512 1
+# endif
+#endif
+
 /* Assembly implementations use SystemV ABI, ABI conversion and additional
  * stack to store XMM6-XMM15 needed on Win64. */
 #undef ASM_FUNC_ABI
 #if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) || \
     defined(USE_GFNI_AVX2) || defined(USE_GFNI_AVX512) || \
-    defined(USE_INTEL_SM4_AVX2)
+    defined(USE_INTEL_SM4_AVX2) || defined(USE_INTEL_SM4_AVX512)
 # ifdef HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS
 #  define ASM_FUNC_ABI __attribute__((sysv_abi))
 # else
@@ -182,6 +192,9 @@ typedef struct
 #ifdef USE_INTEL_SM4_AVX2
   unsigned int use_intel_sm4_avx2:1;
 #endif
+#ifdef USE_INTEL_SM4_AVX512
+  unsigned int use_intel_sm4_avx512:1;
+#endif
 #ifdef USE_AARCH64_SIMD
   unsigned int use_aarch64_simd:1;
 #endif
@@ -419,6 +432,38 @@ sm4_intel_avx2_crypt_blk1_16(void *rk, byte *out, const byte *in,
 }
 #endif /* USE_INTEL_SM4_AVX2 */
 
+#ifdef USE_INTEL_SM4_AVX512
+extern void _gcry_sm4_intel_avx512_ctr_enc_blk32(const u32 *rk_enc, byte *out,
+						 const byte *in,
+						 byte *ctr) ASM_FUNC_ABI;
+
+extern void _gcry_sm4_intel_avx512_cbc_dec_blk32(const u32 *rk_dec, byte *out,
+						 const byte *in,
+						 byte *iv) ASM_FUNC_ABI;
+
+extern void _gcry_sm4_intel_avx512_cfb_dec_blk32(const u32 *rk_enc, byte *out,
+						 const byte *in,
+						 byte *iv) ASM_FUNC_ABI;
+
+extern void _gcry_sm4_intel_avx512_ocb_enc_blk32(const u32 *rk_enc,
+						 unsigned char *out,
+						 const unsigned char *in,
+						 unsigned char *offset,
+						 unsigned char *checksum,
+						 const u64 Ls[32]) ASM_FUNC_ABI;
+
+extern void _gcry_sm4_intel_avx512_ocb_dec_blk32(const u32 *rk_dec,
+						 unsigned char *out,
+						 const unsigned char *in,
+						 unsigned char *offset,
+						 unsigned char *checksum,
+						 const u64 Ls[32]) ASM_FUNC_ABI;
+
+extern unsigned int
+_gcry_sm4_intel_avx512_crypt_blk32(u32 *rk, byte *out,
+				   const byte *in) ASM_FUNC_ABI;
+#endif /* USE_INTEL_SM4_AVX512 */
+
 #ifdef USE_GFNI_AVX2
 extern void _gcry_sm4_gfni_avx2_expand_key(const byte *key, u32 *rk_enc,
                                            u32 *rk_dec, const u32 *fk,
@@ -873,6 +918,9 @@ sm4_setkey (void *context, const byte *key, const unsigned keylen,
 #ifdef USE_INTEL_SM4_AVX2
   ctx->use_intel_sm4_avx2 = (hwf & HWF_INTEL_SM4) && (hwf & HWF_INTEL_AVX2);
 #endif
+#ifdef USE_INTEL_SM4_AVX512
+  ctx->use_intel_sm4_avx512 = (hwf & HWF_INTEL_SM4) && (hwf & HWF_INTEL_AVX512);
+#endif
 #ifdef USE_AARCH64_SIMD
   ctx->use_aarch64_simd = !!(hwf & HWF_ARM_NEON);
 #endif
@@ -1188,6 +1236,21 @@ _gcry_sm4_ctr_enc(void *context, unsigned char *ctr,
   const byte *inbuf = inbuf_arg;
   int burn_stack_depth = 0;
 
+#ifdef USE_INTEL_SM4_AVX512
+  if (ctx->use_intel_sm4_avx512)
+    {
+      /* Process data in 32 block chunks. */
+      while (nblocks >= 32)
+        {
+          _gcry_sm4_intel_avx512_ctr_enc_blk32(ctx->rkey_enc, outbuf, inbuf, ctr);
+
+          nblocks -= 32;
+          outbuf += 32 * 16;
+          inbuf += 32 * 16;
+        }
+    }
+#endif
+
 #ifdef USE_INTEL_SM4_AVX2
   if (ctx->use_intel_sm4_avx2)
     {
@@ -1353,6 +1416,21 @@ _gcry_sm4_cbc_dec(void *context, unsigned char *iv,
   const unsigned char *inbuf = inbuf_arg;
   int burn_stack_depth = 0;
 
+#ifdef USE_INTEL_SM4_AVX512
+  if (ctx->use_intel_sm4_avx512)
+    {
+      /* Process data in 32 block chunks. */
+      while (nblocks >= 32)
+        {
+          _gcry_sm4_intel_avx512_cbc_dec_blk32(ctx->rkey_dec, outbuf, inbuf, iv);
+
+          nblocks -= 32;
+          outbuf += 32 * 16;
+          inbuf += 32 * 16;
+        }
+    }
+#endif
+
 #ifdef USE_INTEL_SM4_AVX2
   if (ctx->use_intel_sm4_avx2)
     {
@@ -1517,6 +1595,21 @@ _gcry_sm4_cfb_dec(void *context, unsigned char *iv,
   const unsigned char *inbuf = inbuf_arg;
   int burn_stack_depth = 0;
 
+#ifdef USE_INTEL_SM4_AVX512
+  if (ctx->use_intel_sm4_avx512)
+    {
+      /* Process data in 32 block chunks. */
+      while (nblocks >= 32)
+        {
+          _gcry_sm4_intel_avx512_cfb_dec_blk32(ctx->rkey_enc, outbuf, inbuf, iv);
+
+          nblocks -= 32;
+          outbuf += 32 * 16;
+          inbuf += 32 * 16;
+        }
+    }
+#endif
+
 #ifdef USE_INTEL_SM4_AVX2
   if (ctx->use_intel_sm4_avx2)
     {
@@ -1679,6 +1772,12 @@ sm4_crypt_blk1_32 (SM4_context *ctx, byte *outbuf, const byte *inbuf,
 
   gcry_assert (num_blks <= 32);
 
+#ifdef USE_INTEL_SM4_AVX512
+  if (num_blks == 32 && ctx->use_intel_sm4_avx512)
+    {
+      return _gcry_sm4_intel_avx512_crypt_blk32 (rk, outbuf, inbuf);
+    }
+#endif
 #ifdef USE_GFNI_AVX512
   if (num_blks == 32 && ctx->use_gfni_avx512)
     {
@@ -1837,6 +1936,39 @@ _gcry_sm4_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
   u64 blkn = c->u_mode.ocb.data_nblocks;
   int burn_stack_depth = 0;
 
+#ifdef USE_INTEL_SM4_AVX512
+  if (ctx->use_intel_sm4_avx512)
+    {
+      u64 Ls[32];
+      u64 *l;
+
+      if (nblocks >= 32)
+	{
+          l = bulk_ocb_prepare_L_pointers_array_blk32 (c, Ls, blkn);
+
+	  /* Process data in 32 block chunks. */
+	  while (nblocks >= 32)
+	    {
+	      blkn += 32;
+	      *l = (uintptr_t)(void *)ocb_get_l (c, blkn - blkn % 32);
+
+	      if (encrypt)
+		_gcry_sm4_intel_avx512_ocb_enc_blk32 (ctx->rkey_enc, outbuf,
+                                                      inbuf, c->u_iv.iv,
+                                                      c->u_ctr.ctr, Ls);
+	      else
+		_gcry_sm4_intel_avx512_ocb_dec_blk32 (ctx->rkey_dec, outbuf,
+                                                      inbuf, c->u_iv.iv,
+                                                      c->u_ctr.ctr, Ls);
+
+	      nblocks -= 32;
+	      outbuf += 32 * 16;
+	      inbuf += 32 * 16;
+	    }
+	}
+    }
+#endif
+
 #ifdef USE_INTEL_SM4_AVX2
   if (ctx->use_intel_sm4_avx2)
     {
diff --git a/configure.ac b/configure.ac
index f12b590e..604f063e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3874,6 +3874,7 @@ if test "$found" = "1" ; then
          GCRYPT_ASM_CIPHERS="$GCRYPT_ASM_CIPHERS sm4-gfni-avx2-amd64.lo"
          GCRYPT_ASM_CIPHERS="$GCRYPT_ASM_CIPHERS sm4-gfni-avx512-amd64.lo"
          GCRYPT_ASM_CIPHERS="$GCRYPT_ASM_CIPHERS sm4-intel-avx2-amd64.lo"
+         GCRYPT_ASM_CIPHERS="$GCRYPT_ASM_CIPHERS sm4-intel-avx512-amd64.lo"
       ;;
       aarch64-*-*)
          # Build with the assembly implementation
-- 
2.53.0




More information about the Gcrypt-devel mailing list