The SM3 Algorithm
SM3 is the Chinese national standard hash function. It looks like SHA-256 at first glance, but its message expansion, step function, and 16 rounds of pure XOR are different. Learn how it works step by step, with every intermediate value checked against the standard.
Pashalis Laoutaris 14 min read
Try it
Interactive SM3 Hash Visualizer
🔐 SM3 Hash
The SM3 Algorithm
Introduction
SM3 is a cryptographic hash function from China. It takes a message of any length and returns a 256-bit digest. It is one of the “ShangMi” (commercial cryptography) algorithms, together with the SM2 signature scheme and the SM4 block cipher. Inside China, it is the only hash function approved for commercial use.
If you know SHA-256, SM3 will feel familiar. It reads 64-byte blocks, keeps eight 32-bit words of state, and runs 64 rounds per block. The details differ, though. The message expansion is more complex, each round uses two words of the expanded message, and the state is scrambled with extra rotations and a permutation. This guide walks through all of it, step by step. The FAQ answers the question of whether SM3 is the same as SHA-256.
Table of Contents
- History and Standards
- Padding
- Message Expansion
- Functions and Constants
- The 64 Rounds
- Interactive Visualizer
- A Worked Example
- Python Implementation
- Security Status
- FAQ
- References
History and Standards
The State Cryptography Administration of China (SCA), which was called OSCCA at the time, first published SM3 in 2010. It was designed by Xiaoyun Wang and colleagues. Wang is also known for the 2004 collision attacks on MD4, MD5, and RIPEMD. In 2012 SM3 became an industry standard, GM/T 0004-2012. In 2016 it became the Chinese national standard GB/T 32905-2016.
SM3 is also an international standard. ISO/IEC 10118-3:2018 includes it among the dedicated hash functions. The IETF has an informational draft that describes it in English, with worked examples. RFC 8998 uses it in the ShangMi cipher suites for TLS 1.3. The names of these suites, TLS_SM4_GCM_SM3 and TLS_SM4_CCM_SM3, show that SM3 is the hash and SM4 is the cipher.
The designers aimed to match or beat SHA-256 in speed while meeting the security requirements. The structure is similar to SHA-256, but the step function and the message input are new. The standard says that these changes help the avalanche effect start earlier and make attacks harder.
Padding
SM3 pads exactly like SHA-256, with a big-endian length. It follows the Merkle-Damgard construction, so the message must become a whole number of 64-byte blocks:
- Append one byte
0x80, which is a one bit followed by zeros. - Append zero bytes until the length is 8 bytes short of a multiple of 64.
- Append the original message length in bits, as an 8-byte big-endian number.
A message of 55 bytes or fewer needs one block. A message of 56 to 119 bytes needs two.
The chaining value starts from eight fixed words. For SM3 they are:
7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e
Message Expansion
Each 64-byte block is read as sixteen big-endian words W[0] to W[15]. The expansion extends them to 68 words with this rule, for j from 16 to 67:
W[j] = P1( W[j-16] xor W[j-9] xor rol(W[j-3], 15) ) xor rol(W[j-13], 7) xor W[j-6]
It then makes 64 more words, W'[j] = W[j] xor W[j+4], for j from 0 to 63. A round with number j uses both W[j] and W'[j]. This is the “double-word message input” that the designers mention. Each round mixes in two message words, where SHA-256 uses one. The designers say this makes the avalanche effect start earlier.
Functions and Constants
SM3 has two permutation functions, two Boolean functions, and two constants:
P0(X) = X xor rol(X, 9) xor rol(X, 17)
P1(X) = X xor rol(X, 15) xor rol(X, 23)
| Rounds | T(j) | FF(x, y, z) | GG(x, y, z) |
|---|---|---|---|
| 0 to 15 | 0x79CC4519 |
x xor y xor z |
x xor y xor z |
| 16 to 63 | 0x7A879D8A |
(x and y) or (x and z) or (y and z) |
(x and y) or (not x and z) |
The first 16 rounds are pure XOR, because both Boolean functions are plain XOR there. After that, FF becomes the majority function and GG becomes the choice function, as in SHA-256. The constant T(j) is rotated left by j mod 32 bits in the round that uses it, so the value changes from round to round. It does not become unique in every round. The rotation depends only on j mod 32, so round 16 and round 48 use the same value, and so do rounds 17 and 49, up to rounds 31 and 63. Across the 64 rounds there are 48 different values.
The 64 Rounds
The state has eight words, A to H. They start from the chaining value. For each round j, from 0 to 63:
SS1 = rol( rol(A, 12) + E + rol(T(j), j mod 32), 7 )
SS2 = SS1 xor rol(A, 12)
TT1 = FF(A, B, C) + D + SS2 + W'[j]
TT2 = GG(E, F, G) + H + SS1 + W[j]
D = C
C = rol(B, 9)
B = A
A = TT1
H = G
G = rol(F, 19)
F = E
E = P0(TT2)
All additions are modulo 2^32. Notice how B and F are rotated as they move along. In SHA-256, words move along the register without any change. Here, two of them are rotated at every step, and E goes through the permutation P0. That is what the standard calls a more complex step function.
After the 64 rounds, SM3 does not add the new state to the old one, and it XORs them instead:
V(new) = V(old) xor (A, B, C, D, E, F, G, H)
After the last block, the eight words are written as big-endian bytes. That is the digest.
Interactive Visualizer
The visualizer above runs this exact algorithm. Type any message of up to 119 bytes and click Hash. The log shows the padding, the start of each block, all 64 rounds with the eight state words, and the final XOR. For each round, the note gives the two message words W[j] and W'[j]. When it ends, the page tells you how many of the 256 digest bits change when one bit of your message is flipped.
A Worked Example
This follows the message abc, which is Example 1 of the standard.
Padding. The three bytes are 61 62 63. After padding, the block is:
61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018
So W[0] = 61626380, W[1] to W[14] are zero, and W[15] = 00000018, which is the length 24 bits.
Expansion. For W[16], the rule needs W[0], W[7], W[13], W[3], and W[10]. Only W[0] is not zero, so the input of P1 is 61626380, and P1 turns it into 9092e200. The other two terms are zero, so W[16] = 9092e200. The next words are W[17] = 00000000, W[18] = 000c0606, and W[19] = 719c70ed. The last word is W[67] = b99c0545. The first extra word is W'[0] = 61626380, and W'[12] = W[12] xor W[16] = 9092e200.
Round 1. The state starts as 7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e. Here rol(A, 12) = 0166f738, and for j = 0 the constant stays 79cc4519. Adding E and rotating the sum by 7 gives SS1 = 51368692. Next comes SS2 = 505071aa, which is SS1 xor rol(A, 12). With the XOR functions, FF = 2db0e601 and GG = 5cd3e65b. These give TT1 = b9edc12b and TT2 = c067debb. Applying P0 to TT2 gives the new E, b2ad29f4. The state is now:
b9edc12b 7380166f 29657292 172442d7 b2ad29f4 a96f30bc c550b189 e38dee4d
After round 2 the state is ea52428c b9edc12b 002cdee7 29657292 ac353a23 b2ad29f4 85e54b79 c550b189. After round 17, the first with the majority function, it is 796afab1 34d1691e a52ef0f8 92b57849 067550f5 61f99646 c999f74a 2aa0d251. After round 64 it is 1547e69b 2bfa5f60 c6d696bc 069ae2e2 e808f43b 4ac3cf08 caf04e66 3fb0a6ae.
Final XOR. XORing this state with the starting values gives the new chaining value 66c7f0f4 62eeedd9 d1f2d46b dc10e4e2 4167c487 5cf2f7a2 297da02b 8f4ba8e0. Written as big-endian bytes, it is the digest:
66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
All the values above, including every word of the expansion and every one of the 64 round states, are listed in the standard’s own example, and they match.
Avalanche. Flipping one bit of abc changes 125 of the 256 bits. The two sentences The quick brown fox jumps over the lazy dog and ... lazy cog give 5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea and ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098, which differ in 133 bits. The empty message gives 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b.
Python Implementation
This is a complete SM3. The function rounds keeps the state after every round, so you can print the steps shown above.
# sm3.py
#
# SM3, the Chinese national standard hash function (GB/T 32905-2016).
# It has the same overall shape as SHA-256: a 256-bit chaining value, 64-byte
# blocks, big-endian words, and a message expansion. The expansion makes 68
# words, and every round uses two of them, W[j] and W'[j] = W[j] xor W[j+4].
MASK = 0xFFFFFFFF
IV = [0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E]
def rol(x, n):
n %= 32
return ((x << n) | (x >> (32 - n))) & MASK if n else x
def p0(x):
return x ^ rol(x, 9) ^ rol(x, 17)
def p1(x):
return x ^ rol(x, 15) ^ rol(x, 23)
def t(j):
return 0x79CC4519 if j < 16 else 0x7A879D8A
def ff(j, x, y, z):
return x ^ y ^ z if j < 16 else (x & y) | (x & z) | (y & z)
def gg(j, x, y, z):
return x ^ y ^ z if j < 16 else (x & y) | (~x & MASK & z)
def pad(message):
"""Append a one bit, zeros, and the 64-bit big-endian bit length, to a multiple of 64 bytes."""
zeros = (55 - len(message)) % 64 # after the 0x80 byte, the length must end 8 bytes short of a multiple of 64
padded = message + b"\x80" + bytes(zeros)
return padded + (8 * len(message) % 2**64).to_bytes(8, "big")
def expand(block):
"""Message expansion: 68 words W and 64 words W' = W[j] xor W[j+4]."""
w = [int.from_bytes(block[4 * i:4 * i + 4], "big") for i in range(16)]
for j in range(16, 68):
w.append(p1(w[j - 16] ^ w[j - 9] ^ rol(w[j - 3], 15)) ^ rol(w[j - 13], 7) ^ w[j - 6])
return w, [w[j] ^ w[j + 4] for j in range(64)]
def rounds(v, w, w1):
"""The 64 rounds. Returns the state (A, ..., H) after every round."""
a, b, c, d, e, f, g, h = v
states = []
for j in range(64):
ss1 = rol((rol(a, 12) + e + rol(t(j), j)) & MASK, 7)
ss2 = ss1 ^ rol(a, 12)
tt1 = (ff(j, a, b, c) + d + ss2 + w1[j]) & MASK
tt2 = (gg(j, e, f, g) + h + ss1 + w[j]) & MASK
a, b, c, d = tt1, a, rol(b, 9), c
e, f, g, h = p0(tt2), e, rol(f, 19), g
states.append([a, b, c, d, e, f, g, h])
return states
def compress(v, block):
w, w1 = expand(block)
final = rounds(v, w, w1)[-1]
return [x ^ y for x, y in zip(v, final)]
def sm3(message):
v = list(IV)
padded = pad(message)
for i in range(0, len(padded), 64):
v = compress(v, padded[i:i + 64])
return b"".join(x.to_bytes(4, "big") for x in v)
if __name__ == "__main__":
for text in (b"abc", b"abcd" * 16, b""):
print("SM3(%r) = %s" % (text.decode(), sm3(text).hex()))
Running it produces this output:
SM3('abc') = 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
SM3('abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd') = debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732
SM3('') = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b
I checked this code against several independent sources before writing it up. It reproduces both examples of the standard as printed in the IETF draft: the padded block, all 68 words W, all 64 words W', and all 64 round states, for both blocks of the second example. It also agrees with the OpenSSL that ships with Python on 507 inputs, lengths from 0 to 4096 bytes, and on one million repetitions of the letter a.
Security Status
No feasible attack on the full SM3 is known. The IETF draft says so, and it adds that no formal proof of security is provided. The security of SM3 is studied in public, as it is for SHA-2. Published attacks reach only part of the 64 rounds. This table is the one in the IETF draft of January 2018, and I did not find newer results when I searched:
| Attack | Target | Rounds | Cost |
|---|---|---|---|
| Collision | Hash function | 20 | Practical |
| Free-start collision | Compression function | 24 | Practical |
| Preimage | Hash function | 30 | about 2^249 |
| Boomerang distinguisher | Compression function | 37 | about 2^192 |
The draft lists these results under the name of “steps”, which are the same as rounds. The collision attacks are by Mendel, Nad, and Schlaffer in 2013. The 30-step preimage attack is by Zou and others, and the 37-step boomerang distinguisher is by Bai and others. The full 64 rounds are far out of reach. As a 256-bit hash, SM3 gives about 128 bits of collision resistance. That is the same level as SHA-256.
SM3 is a Merkle-Damgard hash, so it allows length extension. Anyone who knows the digest of an unknown message can compute the digest of that message plus its padding plus more data. Use HMAC-SM3, or another keyed construction, when you need a MAC.
FAQ
Is SM3 the same as SHA-256?
No, they are different functions. Both give 256-bit digests, and both are built from the same family of ideas. But the message expansion, the round function, the constants, the padding of the state, and the final XOR are different. The same input gives completely unrelated digests.
Where is SM3 used?
It is used in China’s commercial cryptography, such as SM2 digital signatures, message authentication codes, and random number generation. Outside China, it appears in the ShangMi cipher suites for TLS 1.3 and in several cryptographic libraries, including OpenSSL.
Why are the first 16 rounds pure XOR?
The designers chose this on purpose. The standard lists the 16 XOR steps among its new design techniques. It says they reduce the sensitivity to locality and help against differential and linear cryptanalysis. After round 16, the nonlinear Boolean functions appear.
Is SM3 safe to use?
As far as public research shows, yes. The attacks reach 37 of 64 rounds at best, and only for weaker properties. Its 256-bit output gives the same collision resistance as SHA-256. Outside of systems that require it, though, SHA-256 or SHA-3 have far more review.
Does SM3 resist length extension?
No, because like SHA-256 and MD5 it is a Merkle-Damgard hash with the full state as output. Use HMAC when you need to authenticate a message.
References
-
Standardization Administration of China. “GB/T 32905-2016: Information security techniques, SM3 cryptographic hash algorithm.” 2016.
-
Shen, S. and Lee, X. “SM3 Cryptographic Hash Algorithm.” Internet-Draft draft-sca-cfrg-sm3-02, January 2018. Available at: https://datatracker.ietf.org/doc/draft-sca-cfrg-sm3/
-
Yang, P. “ShangMi (SM) Cipher Suites for TLS 1.3.” RFC 8998, 2021. Available at: https://www.rfc-editor.org/rfc/rfc8998
-
ISO/IEC 10118-3:2018. “Information security, Hash-functions, Part 3: Dedicated hash-functions.”
-
Wang, X. and Yu, H. “SM3 Cryptographic Hash Algorithm.” October 2016. Available at: http://ris.sic.gov.cn/EN/Y2016/V2/I11/983
-
Mendel, F., Nad, T., and Schlaffer, M. “Finding Collisions for Round-Reduced SM3.” 2013. Available at: https://doi.org/10.1007/978-3-642-36095-4_12
-
Zou, J., Wu, W., Wu, S., Su, B., and Dong, L. “Preimage Attacks on Step-Reduced SM3 Hash Function.” ICISC 2011. Available at: https://doi.org/10.1007/978-3-642-31912-9_25
-
Kircanski, A., Shen, Y., Wang, G., and Youssef, A. “Boomerang and Slide-Rotational Analysis of the SM3 Hash Function.” SAC 2012. Available at: https://eprint.iacr.org/2012/274
-
Bai, D., Yu, H., Wang, G., and Wang, X. “Improved Boomerang Attacks on Round-Reduced SM3 and Keyed Permutation of BLAKE-256.” IET Information Security, 2015. Available at: https://doi.org/10.1049/iet-ifs.2013.0380
-
Wikipedia. “SM3 (hash function).” Available at: https://en.wikipedia.org/wiki/SM3_(hash_function)