动机
当前 ZUC 的 amd64 实现(internal/zuc/asm_amd64.s)采用 VPSHUFB 查表法和 AES-NI 计算 S0/S1 两个 S-box,每 16 字节需要约 19 条指令(S0) 和 18 条指令(S1):
S0(复合域 GF((2^4)^2) 实现):
// 约 19 条指令:nibble 拆分 → P1/P2/P3 查表 → 重组 → Rotl_5(字节内循环左移5位)
VPSRLQ $4, IN_OUT, XTMP1
VPAND Low_nibble_mask, ...
VMOVDQU P1, XTMP2 ; VPSHUFB ; VPXOR // P1[x2] ⊕ x1
VMOVDQU P2, ... ; VPSHUFB ; VPXOR // P2[q] ⊕ x2
VMOVDQU P3, ... ; VPSHUFB ; VPXOR // P3[r] ⊕ q
VPSLLQ $4 ; VPOR // 重组
// Rotl_5: VPSLLD + VPSRLD + VPAND×2 + VPOR(5条)
S1(AES-NI 实现):
// 约 18 条指令:ZUC域→AES域映射 → VAESENCLAST → AES域→ZUC域映射
// 代码注释已标注 GFNI 等价:
// gf2p8affineqb XIN_OUT, [rel Aes_to_Zuc], 0x00 ← 等价替换1
VMOVDQU Aes_to_Zuc_mul_low_nibble, XTMP1
VMOVDQU Aes_to_Zuc_mul_high_nibble, XTMP2
MUL_PSHUFB_AVX(...) // 6条 VPSHUFB/VPAND/VPXOR
VPSHUFB Shuf_mask, XTMP2, XTMP2
VAESENCLAST Cancel_aes, XTMP2, XTMP2 // AES SubBytes(含域变换消除)
// gf2p8affineqb XIN_OUT, [rel CombMatrix], 0x55 ← 等价替换2
VMOVDQU Comb_matrix_mul_low_nibble, XTMP1
VMOVDQU Comb_matrix_mul_high_nibble, XIN_OUT
MUL_PSHUFB_AVX(...) // 6条
GFNI 可将两个 S-box 各压缩至 2 条指令,且原生支持 VEX-256(32 字节并行),无需额外的 128→256 位扩展。
预期收益
| S-box |
当前方案 |
GFNI 方案 |
指令减少 |
| S0 |
~19 条(VPSHUFB查表 + Rotl_5) |
2 条 |
90% ↓ |
| S1 |
~18 条(MUL_PSHUFB×2 + VAESENCLAST) |
2 条 |
89% ↓ |
预期对 ZUC EEA(加密)和 EIA(完整性)吞吐量均有显著提升,量级参考 SM4 GFNI 优化(1.5–2×)。
S1 S-box GFNI 方案(已验证)
已通过 emmansun/simd 验证,且 internal/zuc/asm_amd64.s 源码注释中已标注等价形式。
S1 的数学关系:
S1(x) = m2 · GF_AES_Inv(m1 · x) ⊕ 0x55
GFNI 汇编(2 条指令替代 ~18 条):
VGF2P8AFFINEQB $0x00, Y_m1, Ydata, Ydata // x = m1·x ⊕ 0x00
VGF2P8AFFINEINVQB $0x55, Y_m2, Ydata, Ydata // x = m2·GF_inv(x) ⊕ 0x55
已验证的 8 组矩阵对(c1=0, c2=0x55,均对应完整 ZUC S1 表):
| # |
m1(64位行主序 LE) |
m2(64位行主序 LE) |
| 1 |
0x0F33E408A6F65828 |
0x9581FB0653B61C09 |
| 2 |
0x2B3E78B290E2AA3C |
0x0E95DF5D48F66EAB |
| 3 |
0x95124E5A9E18ACC6 |
0xC305CBCC771ADAF1 |
| 4 |
0x0BF1A8BCA6D25E0C |
0xC1A71BBED5BA082D |
| 5 |
0xDD06C8F01EAE7C70 |
0x0B903E360F14F0E3 |
| 6 |
0x1106DCE4D4485096 |
0x6973993A7FB45C4D |
| 7 |
0x47F4C026028C6E52 |
0x293F6F5E93664AD1 |
| 8 |
0xA7F40AEC16B4426A |
0x27916DF23DC646A1 |
⚠️ 上表矩阵值根据 simd 测试文件内容重建,需以 simd 仓库原始 Go 源码为准。
验证:S1(0) = m2 · GF_inv(0) ⊕ 0x55 = 0 ⊕ 0x55 = 0x55,与 ZUC 规范 S1(0)=0x55 一致 ✓
注:VPSHUFB Shuf_mask 的 ShiftRows 效果和 Cancel_aes (0x63) 抵消已并入 m1 矩阵编码中(与 SM4 GFNI 的矩阵吸收方式相同)。
S0 S-box GFNI 方案(不可行)
ZUC S0 定义在 GF(2^8) 上(多项式 p(x) = x^8+x^4+x^3+x^2+1),通过复合域 GF((2^4)^2) 分解计算逆元,再叠加字节内 5 位循环左移(Rotl_5)。
关键结论:ZUC S0 不可以用 GFNI 实现。
数学依据(已通过计算验证):
- ZUC S0 的差分均匀度(Differential Uniformity)为 8,而 GF(2^8) 乘法逆元(AES S-box 的核心)的差分均匀度为 4
- 仿射等价的 S-box 具有相同的差分均匀度(仿射变换保持差分均匀度不变)
- 因此 ZUC S0 不仿射等价于任何 GF(2^8) 域逆元,无法表示为
M2·GF_AES_inv(M1·x⊕c1)⊕c2 的形式
- 计算验证:枚举 p(x) 在 AES GF(2^8) 中的全部 8 个根(0x03, 0x05, 0x11, 0x1a, 0x4c, 0x5f, 0xe5, 0xfb)作为基变换矩阵 M1,对所有 c1∈{0..255} 穷举,均未找到满足条件的 (M1, M2, c1, c2)
结论:GFNI 只能加速 ZUC S1,ZUC S0 只能继续使用 VPSHUFB 复合域实现。
emmansun/simd 仓库同样只有 ZUC S1(zuc.SBOX)的 GFNI 测试,未提供 S0 参数,与此结论一致。
VEX-256 优势
与 SM4 不同,ZUC 的 SSE 实现每次处理 16 字节(128 位),GFNI 支持 VEX-256(256 位),可将并行度提升到 32 字节:
// VEX-256 GFNI S1(32字节并行)
VGF2P8AFFINEQB $0x00, Ymm_Aes_to_Zuc, Ydata, Ydata // 32字节一次完成
VGF2P8AFFINEINVQB $0x55, Ymm_CombMatrix, Ydata, Ydata
但 ZUC 算法本身每轮生成 32 位输出,需要评估 32 字节并行处理的实际收益(多路 ZUC 流并行时更有意义)。
前提条件
实现状态(已完成)
ZUC GFNI 优化已完全实现(仅 S1;S0 因差分均匀度为 8 不支持 GFNI):
-
S1 GFNI 实现(已完成):
- 选用第 3 组矩阵对(
m1=0x95124E5A9E18ACC6, m2=0xC305CBCC771ADAF1,c1=0, c2=0x55)
- 在
internal/zuc/asm_amd64.s 中添加了 S1_comput_GFNI 宏(2 条指令替代 ~18 条)
- 添加了
NONLIN_FUN_GFNI, ROUND_GFNI, ROUND_REV32_GFNI 宏
- 在
genKeywordAsm, genKeyStreamAsm, genKeyStreamRev32Asm 中添加了 GFNI dispatch
- 在
internal/zuc/core_asm.go 中添加了 useGFNI 变量
- 所有测试通过(
go test ./internal/zuc/ ./zuc/)
- 性能提升:~410 MB/s(GFNI)vs ~240 MB/s(SSE,无 AVX/GFNI)≈ 1.7x
-
S0 分析(已完成,结论为不适用):
- ZUC S0 差分均匀度为 8(非仿射等价于域逆元),GFNI 不适用
- ZUC S0 继续使用现有 VPSHUFB 复合域实现
当前 ZUC S-box 指令计数(16字节/批次)
| S-box |
常量加载 |
VPSHUFB/PSHUFB |
其他 |
合计 |
| S0 |
3 (P1/P2/P3) |
3 |
13 (VPXOR×3, VPAND×3, VPSRLQ, VPSLLQ, VPOR, Rotl_5×5) |
~19 |
| S1 |
4 |
7 (MUL_PSHUFB×2×3 + Shuf_mask) |
3 (VAESENCLAST, VPXOR×2) |
~18 |
| GFNI |
0 |
0 |
2 |
2 |
参考资料
动机
当前 ZUC 的 amd64 实现(
internal/zuc/asm_amd64.s)采用 VPSHUFB 查表法和 AES-NI 计算 S0/S1 两个 S-box,每 16 字节需要约 19 条指令(S0) 和 18 条指令(S1):S0(复合域 GF((2^4)^2) 实现):
S1(AES-NI 实现):
GFNI 可将两个 S-box 各压缩至 2 条指令,且原生支持 VEX-256(32 字节并行),无需额外的 128→256 位扩展。
预期收益
预期对 ZUC EEA(加密)和 EIA(完整性)吞吐量均有显著提升,量级参考 SM4 GFNI 优化(1.5–2×)。
S1 S-box GFNI 方案(已验证)
已通过 emmansun/simd 验证,且
internal/zuc/asm_amd64.s源码注释中已标注等价形式。S1 的数学关系:
GFNI 汇编(2 条指令替代 ~18 条):
已验证的 8 组矩阵对(c1=0, c2=0x55,均对应完整 ZUC S1 表):
0x0F33E408A6F658280x9581FB0653B61C090x2B3E78B290E2AA3C0x0E95DF5D48F66EAB0x95124E5A9E18ACC60xC305CBCC771ADAF10x0BF1A8BCA6D25E0C0xC1A71BBED5BA082D0xDD06C8F01EAE7C700x0B903E360F14F0E30x1106DCE4D44850960x6973993A7FB45C4D0x47F4C026028C6E520x293F6F5E93664AD10xA7F40AEC16B4426A0x27916DF23DC646A1验证:
S1(0) = m2 · GF_inv(0) ⊕ 0x55 = 0 ⊕ 0x55 = 0x55,与 ZUC 规范 S1(0)=0x55 一致 ✓注:
VPSHUFB Shuf_mask的 ShiftRows 效果和Cancel_aes(0x63) 抵消已并入 m1 矩阵编码中(与 SM4 GFNI 的矩阵吸收方式相同)。S0 S-box GFNI 方案(不可行)
ZUC S0 定义在 GF(2^8) 上(多项式 p(x) = x^8+x^4+x^3+x^2+1),通过复合域 GF((2^4)^2) 分解计算逆元,再叠加字节内 5 位循环左移(Rotl_5)。
关键结论:ZUC S0 不可以用 GFNI 实现。
数学依据(已通过计算验证):
M2·GF_AES_inv(M1·x⊕c1)⊕c2的形式结论:GFNI 只能加速 ZUC S1,ZUC S0 只能继续使用 VPSHUFB 复合域实现。
VEX-256 优势
与 SM4 不同,ZUC 的 SSE 实现每次处理 16 字节(128 位),GFNI 支持 VEX-256(256 位),可将并行度提升到 32 字节:
但 ZUC 算法本身每轮生成 32 位输出,需要评估 32 字节并行处理的实际收益(多路 ZUC 流并行时更有意义)。
前提条件
HasGFNI检测已实现(internal/cpuid/cpuid_amd64.go)VGF2P8AFFINEQB/VGF2P8AFFINEINVQB(XMM/YMM)internal/sm4/gfni_macros_amd64.s)实现状态(已完成)
ZUC GFNI 优化已完全实现(仅 S1;S0 因差分均匀度为 8 不支持 GFNI):
S1 GFNI 实现(已完成):
m1=0x95124E5A9E18ACC6,m2=0xC305CBCC771ADAF1,c1=0, c2=0x55)internal/zuc/asm_amd64.s中添加了S1_comput_GFNI宏(2 条指令替代 ~18 条)NONLIN_FUN_GFNI,ROUND_GFNI,ROUND_REV32_GFNI宏genKeywordAsm,genKeyStreamAsm,genKeyStreamRev32Asm中添加了 GFNI dispatchinternal/zuc/core_asm.go中添加了useGFNI变量go test ./internal/zuc/ ./zuc/)S0 分析(已完成,结论为不适用):
当前 ZUC S-box 指令计数(16字节/批次)
参考资料