国家标准全文公开系统:http://openstd.samr.gov.cn/
本文参考:http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=45B1A67F20F3BF339211C391E9278F5E
常数与函数
-
初值 I V = 7380166 F , 4914 B 2 B 9 , 172442 D 7 , D A 8 A 0600 , A 96 F 30 B C , 163138 A A , E 38 D E E 4 D , B 0 F B 0 E 4 E IV = 7380166F,4914B2B9,172442D7,DA8A0600,A96F30BC,163138AA,E38DEE4D,B0FB0E4E IV=7380166F,4914B2B9,172442D7,DA8A0600,A96F30BC,163138AA,E38DEE4D,B0FB0E4E
-
常量 T 0 = 79 C C 4519 , T 1 = 7 A 879 D 8 A T_0 = 79CC4519,\,T_1 = 7A879D8A T0=79CC4519,T1=7A879D8A
-
布尔函数
F F 0 ( X , Y , Z ) = X ⊕ Y ⊕ Z 模 2 加 法 F F 1 ( X , Y , Z ) = ( X ∧ Y ) ∨ ( X ∧ Z ) ∨ ( Y ∧ Z ) 少 数 服 从 多 数 G G 0 ( X , Y , Z ) = X ⊕ Y ⊕ Z 模 2 加 法 G G 1 ( X , Y , Z ) = ( X ∧ Y ) ∨ ( ¬ X ∧ Z ) 用 X 选 择 Y 或 Z \begin{aligned} FF_0(X,Y,Z) =& X \oplus Y \oplus Z & 模2加法\\ FF_1(X,Y,Z) =& (X \wedge Y) \vee (X \wedge Z) \vee (Y \wedge Z) & 少数服从多数\\ GG_0(X,Y,Z) =& X \oplus Y \oplus Z & 模2加法\\ GG_1(X,Y,Z) =& (X \wedge Y) \vee (\neg X \wedge Z) & 用X选择Y或Z\\ \end{aligned} FF0(X,Y,Z)=FF1(X,Y,Z)=GG0(X,Y,Z)=GG1(X,Y,Z)=X⊕Y⊕Z(X∧Y)∨(X∧Z)∨(Y∧Z)X⊕Y⊕Z(X∧Y)∨(¬X∧Z)模2加法少数服从多数模2加法用X选择Y或Z -
置换函数
P 0 ( X ) = X ⊕ ( X ≪ 9 ) ⊕ ( X ≪ 17 ) P 1 ( X ) = X ⊕ ( X ≪ 15 ) ⊕ ( X ≪ 23 ) \begin{aligned} P_0(X) =& X \oplus (X \ll 9) \oplus (X \ll 17) \\ P_1(X) =& X \oplus (X \ll 15) \oplus (X \ll 23) \\ \end{aligned} P0(X)=P1(X)=X⊕(X≪9)⊕(X≪17)X⊕(X≪15)⊕(X≪23) -
其中 X , Y , Z X,Y,Z X,Y,Z都是字,运算符 ≪ \ll ≪是字的循环左移。
-
S M 3 SM3 SM3处理的单位是字 (1 Word = 32 bits),按大端存储 (左边是高有效位)
消息扩展
-
将 512 512 512比特的消息分组 (含 16 16 16个字 W 0 , W 1 , ⋯ , W 15 W_0,W_1,\cdots,W_{15} W0,W1,⋯,W15),扩展成 132 132 132个字 W 0 , W 1 , ⋯ , W 67 , W 0 ′ , W 1 ′ , ⋯ , W 63 ′ W_0,W_1,\cdots,W_{67},W_0',W_1',\cdots,W_{63}' W0,W1,⋯,W67,W0′,W1′,⋯,W63′
-
对于 i = 16 , 17 , ⋯ , 67 i=16,17,\cdots,67 i=16,17,⋯,67,计算 W i = P 1 ( W i − 16 ⊕ W i − 9 ⊕ ( W i − 3 ≪ 15 ) ) ⊕ ( W i − 13 ≪ 7 ) ⊕ W i − 6 W_i = P_1(W_{i-16} \oplus W_{i-9} \oplus (W_{i-3} \ll 15)) \oplus (W_{i-13} \ll 7) \oplus W_{i-6} Wi=P1(Wi−16⊕Wi−9⊕(Wi−3≪15))⊕(Wi−13≪7)⊕Wi−6
-
对于 j = 0 , 1 , ⋯ , 63 j = 0,1,\cdots,63 j=0,1,⋯,63,计算 W j ′ = W j ⊕ W j + 4 W_j' = W_j \oplus W_{j+4} Wj′=Wj⊕Wj+4
压缩函数
-
这是固定输入长度 512 512 512比特的压缩函数,输出为 256 256 256比特的杂凑值。
-
记为 V ′ = C F ( V , B ) V' = CF(V,B) V′=CF(V,B),其中 V , V ′ V,V' V,V′为中间变量, B B B为 512 512 512比特的输入。
-
令 A B C D E F G H ← V ABCDEFGH \leftarrow V ABCDEFGH←V,其中 A , B , ⋯ A,B,\cdots A,B,⋯为 32 32 32比特的字。
-
一共要执行 64 64 64轮迭代,然后 V ′ ← A B C D E F G H ⊕ V V' \leftarrow ABCDEFGH \oplus V V′←ABCDEFGH⊕V
-
对于 0 ≤ j ≤ 15 0 \le j \le 15 0≤j≤15的迭代,使用 T 0 , F F 0 , G G 0 T_0,FF_0,GG_0 T0,FF0,GG0和 P 0 P_0 P0
-
对于 16 ≤ j ≤ 63 16 \le j \le 63 16≤j≤63的迭代,使用 T 1 , F F 1 , G G 1 T_1,FF_1,GG_1 T1,FF1,GG1和 P 0 P_0 P0
for (j = 0; j < 16; j++)
{
SS1 = ROTL((ROTL(A, 12) + E + ROTL(T0, j)), 7);
SS2 = SS1 ^ ROTL(A, 12);
TT1 = FF0(A, B, C) + D + SS2 + W1[j];
TT2 = GG0(E, F, G) + H + SS1 + W[j];
D = C;
C = ROTL(B, 9);
B = A;
A = TT1;
H = G;
G = ROTL(F, 19);
F = E;
E = P0(TT2);
}
for (j = 16; j < 64; j++)
{
SS1 = ROTL((ROTL(A, 12) + E + ROTL(T1, j)), 7);
SS2 = SS1 ^ ROTL(A, 12);
TT1 = FF1(A, B, C) + D + SS2 + W1[j];
TT2 = GG1(E, F, G) + H + SS1 + W[j];
D = C;
C = ROTL(B, 9);
B = A;
A = TT1;
H = G;
G = ROTL(F, 19);
F = E;
E = P0(TT2);
}
填充
- 对于 l < 2 64 l < 2^{64} l<264比特长度的消息 m m m,计算 k = min { k ≥ 0 ∣ l + 1 + k ≡ 448 m o d 512 } k = \min\{k \ge 0 \mid l+1+k \equiv 448 \mod 512\} k=min{k≥0∣l+1+k≡448mod512}
- 做填充: m ′ = m ∥ 1 ∥ 0 ⋯ 0 ⏟ k ∥ l m' = m \| 1 \| \underbrace{0 \cdots 0}_{k} \| l m′=m∥1∥k 0⋯0∥l,其中 l l l是 64 64 64比特的无符号整数。
- 填充后的消息 m ′ m' m′长度为 512 512 512的倍数 l ′ l' l′,它的最后 64 64 64比特是消息长度,然后继续向前找到第一个遇到的 1 1 1作为标记,继续往前就是消息 m m m
迭代压缩
- 使用 M e r k l e − D a m g a r d T r a n s f o r m Merkle-Damgard\,\,\,\,Transform Merkle−DamgardTransform,将固定输入长度的压缩函数,扩展到任意输入长度的压缩函数。
- 假设填充后的 m ′ m' m′长度为 l ′ = 512 n l' = 512n l′=512n,那么可以分成 n n n个 512 512 512比特的消息分组 B ( i ) , i = 0 , 1 , ⋯ , n − 1 B^{(i)},\, i=0,1,\cdots,n-1 B(i),i=0,1,⋯,n−1
- 初始化 V ( 0 ) = I V V^{(0)} = IV V(0)=IV
- 迭代 V ( i + 1 ) = C F ( V ( i ) , B ( i ) ) V^{(i+1)} = CF(V^{(i)},B^{(i)}) V(i+1)=CF(V(i),B(i)),最后输出 V ( n ) V^{(n)} V(n)
在线计算
- 有时候,我们并不知道要压缩的消息 m m m到底有多长。比如:网络通信中,数据包分批到达。
- 可以记录当前已到达的数据长度,对已到达的数据分组并迭代计算中间变量 V ( j ) V^{(j)} V(j),并存储达不到 512 512 512比特的数据尾部。
- 把填充步骤放在最后执行。当所有数据都到达之后,对数据尾部做填充,并迭代计算出 V ( n ) V^{(n)} V(n)
实现
-
不同计算机的大小端不一致。
-
小端机器上, u i n t 32 n = 0 x 01020304 uint32\,\,n = 0x01020304 uint32n=0x01020304,对应 ( u i n t 8 ∗ ) & n = [ 04 , 03 , 02 , 01 ] (uint8*)\,\,\&n = [04,03,02,01] (uint8∗)&n=[04,03,02,01]
-
本人的笔记本为小端机器,执行 C F CF CF时注意数据的大小端转换。
-
在 C F CF CF中, A → B A \rightarrow B A→B, C → D C \rightarrow D C→D, E → F E \rightarrow F E→F, G → H G \rightarrow H G→H这些赋值不是必要的,可以跨越两轮。赋值运算比加、减、乘、位运算要慢得多。