Instruction
VSM4KEY4
Performs four rounds of SM4 key expansion in each 128-bit lane.
- Extensions
- Forms
- 10 (4 VEX, 6 EVEX)
- Data
- Intel XED v2026.08.23
VSM4KEY4 computes four of SM4’s 32 round keys. SM4 derives them from the 128-bit key MK in a chain much like its rounds: the four key words are first XORed with fixed words FK[0] to FK[3], giving K[0] to K[3], and then
K[i+4] = K[i] ^ T'(K[i+1] ^ K[i+2] ^ K[i+3] ^ CK[i])
for i from 0 to 31, where K[i+4] is round key rk[i]. T’ passes each byte through the same S-box as the rounds of VSM4RNDS4, but then XORs the word only with itself rotated left by 13 and 23 bits. VSM4KEY4 takes K[i] to K[i+3] in its second operand and CK[i] to CK[i+3] in its third, a register or memory, and writes the next four, rk[i] to rk[i+3], to the first.
What software supplies
- FK, before the first instruction. The XOR with FK is one VPXOR of the key with a constant.
- The 32 constants CK[i], four per instruction. They are fixed (byte j of CK[i] is (4i + j) times 7, modulo 256), but VSM4KEY4 does not generate them, as VSM3RNDS2 generates SM3’s; they come from a table of eight 16-byte rows, and the third operand can read each row from memory.
- Byte order. SM4 numbers bytes from the most significant, so a key loaded from memory is byte-swapped in each word first.
Eight VSM4KEY4s give all 32 round keys, each one’s result being the next one’s second operand, and each result is also directly the third operand of one VSM4RNDS4. Decryption uses the same keys in reverse order, rk[31] first, which takes reversing the dwords of each result and the order of the eight registers.
Wider forms
Each 128-bit lane works alone, so the YMM form, and the EVEX form on
ZMM, expand two or four keys at once; with the same key in every lane
they compute the same schedule twice or four times over. The VEX forms
need the SM4 extension (CPUID leaf 7, subleaf 1, EAX bit 2) and AVX, the
EVEX forms AVX10 as well. Zen 5 has neither, and all ten of its recorded
cases raised #UD. GCC 14 and Clang 23 provide _mm_sm4key4_epi32(k, ck)
and the 256-bit form with -msm4.
Forms
| Instruction | Encoding | Requires |
|---|---|---|
VSM4KEY4 xmm, xmm, xmm
VSM4KEY4_XMMu32_XMMu32_XMMu32 | VEX.128.F3.0F38.W0 DA /r | SM4 + AVX |
VSM4KEY4 xmm, xmm, m128
VSM4KEY4_XMMu32_XMMu32_MEMu32 | VEX.128.F3.0F38.W0 DA /r | SM4 + AVX |
VSM4KEY4 ymm, ymm, ymm
VSM4KEY4_YMMu32_YMMu32_YMMu32 | VEX.256.F3.0F38.W0 DA /r | SM4 + AVX |
VSM4KEY4 ymm, ymm, m256
VSM4KEY4_YMMu32_YMMu32_MEMu32 | VEX.256.F3.0F38.W0 DA /r | SM4 + AVX |
VSM4KEY4 xmm, xmm, xmm
VSM4KEY4_XMMu32_XMMu32_XMMu32_AVX512 | EVEX.128.F3.0F38.W0 DA /r | SM4 + AVX10 |
VSM4KEY4 xmm, xmm, m128
VSM4KEY4_XMMu32_XMMu32_MEMu32_AVX512 | EVEX.128.F3.0F38.W0 DA /r | SM4 + AVX10 |
VSM4KEY4 ymm, ymm, ymm
VSM4KEY4_YMMu32_YMMu32_YMMu32_AVX512 | EVEX.256.F3.0F38.W0 DA /r | SM4 + AVX10 |
VSM4KEY4 ymm, ymm, m256
VSM4KEY4_YMMu32_YMMu32_MEMu32_AVX512 | EVEX.256.F3.0F38.W0 DA /r | SM4 + AVX10 |
VSM4KEY4 zmm, zmm, zmm
VSM4KEY4_ZMMu32_ZMMu32_ZMMu32_AVX512 | EVEX.512.F3.0F38.W0 DA /r | SM4 + AVX10 |
VSM4KEY4 zmm, zmm, m512
VSM4KEY4_ZMMu32_ZMMu32_MEMu32_AVX512 | EVEX.512.F3.0F38.W0 DA /r | SM4 + AVX10 |
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
if not cpuid_leaf(7, 1)[0] >> 2 & 1:
fault(UD) # CPUID: no SM4
for i in range(VL // 128): # each lane:
a = ymm2.d[4 * i] # the expansion's
b = ymm2.d[4 * i + 1] # four words,
c = ymm2.d[4 * i + 2] # the first in
d = ymm2.d[4 * i + 3] # dword 0
for j in range(4): # src3: four CK
x = b ^ c ^ d ^ src3.d[4 * i + j]
x = a ^ sm4_l_key(sm4_sub_word(x))
ymm1.d[4 * i + j] = x # the next
a = b
b = c
c = d
d = x
# ymm1 is zeroed from bit VL upRun on AMD Zen 5 (EPYC 9645): 4 cases. Its cases ran where CPUID reported no SM4, and every one raised an exception.
if not cpuid_leaf(7, 1)[0] >> 2 & 1:
fault(UD) # CPUID: no SM4
if not cpuid_leaf(7, 1)[3] >> 19 & 1:
fault(UD) # CPUID: no AVX10
for i in range(VL // 128): # each lane:
a = zmm2.d[4 * i] # the expansion's
b = zmm2.d[4 * i + 1] # four words,
c = zmm2.d[4 * i + 2] # the first in
d = zmm2.d[4 * i + 3] # dword 0
for j in range(4): # src3: four CK
x = b ^ c ^ d ^ src3.d[4 * i + j]
x = a ^ sm4_l_key(sm4_sub_word(x))
zmm1.d[4 * i + j] = x # the next
a = b
b = c
c = d
d = x
# zmm1 is zeroed from bit VL upRun on AMD Zen 5 (EPYC 9645): 6 cases. Its cases ran where CPUID reported no SM4, and every one raised an exception.
Operands
| Operand | Kind | Action |
|---|---|---|
VSM4KEY4 xmm, xmm, xmm/m128 VSM4KEY4 ymm, ymm, ymm/m256 VSM4KEY4 zmm, zmm, zmm/m512 | ||
xmm, ymm, zmm | explicit | write |
xmm, ymm, zmm | explicit | read |
xmm/m128, ymm/m256, zmm/m512 | explicit | read |
Flags
None: XED records no flag that the forms test or change.
Exceptions
The exception class is XED's name for the set of exception conditions that a form follows. How to read.
- VEX forms
avx-type-6- EVEX forms
AVX512-E6
Intrinsics
The C intrinsics of Clang 23.1.2 that compile to VSM4KEY4, each with the form it compiles to and the Clang options it needs. The forms come from compiling every intrinsic and decoding the result with Intel XED; all intrinsics A–Z explains the method.
| Intrinsic | Compiles to |
|---|---|
_mm_sm4key4_epi32
__m128i _mm_sm4key4_epi32(__m128i A, __m128i B) |
|
_mm256_sm4key4_epi32
__m256i _mm256_sm4key4_epi32(__m256i A, __m256i B) |
|
_mm512_sm4key4_epi32
__m512i _mm512_sm4key4_epi32(__m512i __A, __m512i __B) |
|
CPUID and processors
Each form belongs to an XED ISA set. A form can be used when the processor reports every CPUID bit of one of its ISA set's alternatives.
| ISA set | CPUID | Processors |
|---|---|---|
SM4 | SM4 + AVX | Arrow Lake, Panther Lake, Nova Lake, Diamond Rapids, Clearwater Forest Note: Intel's extensions reference introduces these instructions with Arrow Lake S, and GCC's -march=arrowlake, which it selects for Arrow Lake H and U, leaves them out. |
SM4_128 | SM4 + AVX10 | Nova Lake, Diamond Rapids |
SM4_256 | Same as SM4_128 | Same as SM4_128 |
SM4_512 | Same as SM4_128 | Same as SM4_128 |
More SM4 instructions
Sources
- Intel XED v2026.08.23 (commit
0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model. - Clang's x86 intrinsic headers, LLVM 23.1.2 (commit
85ac56026243): the intrinsics, their signatures and doc comments, and the Clang of that release, which compiled each of them. - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2C, page 5-761 (VSM4KEY4)
- Intel Architecture Instruction Set Extensions and Future Features Programming Reference (319433-062, June 2026)
- IETF draft-ribose-cfrg-sm4-10: The SM4 Blockcipher Algorithm and Its Modes of Operations (April 2018)
The tables are derived from Intel XED, Copyright Intel Corporation, licensed under the Apache License 2.0; x86-64.net converted and reformatted them. The intrinsics and their signatures come from Clang, part of the LLVM Project, licensed under the Apache License 2.0 with LLVM Exceptions. The text is our own.