为什么 SSE 中的 AES 没有提供完整的功能?

Why does AES in SSE not provide full function?

Rijndael key schedule procedure涉及RotWordSubWordXOR,都支持 _mm_aeskeygenassist_si128:

X3[31:0] ← SRC [127: 96];
X2[31:0] ← SRC [95: 64];
X1[31:0] ← SRC [63: 32];
X0[31:0] ← SRC [31: 0];
RCON[31:0] ← ZeroExtend(Imm8[7:0]);
DEST[31:0] ← SubWord(X1);
DEST[63:32 ] ← RotWord( SubWord(X1) ) XOR RCON;
DEST[95:64] ← SubWord(X3);
DEST[127:96] ← RotWord( SubWord(X3) ) XOR RCON;
DEST[VLMAX-1:128] (Unmodified)

但是,它不是 return 一个完整的轮密钥。例如,而不是简单地执行

DEST[31:0] <- SubWord(X1),

我想我们应该实际执行

DEST[31:0]<-RotWord(SubWord(X3)) XOR RCON XOR X0.

因此,在_mm_aeskeygenassist_si128之后,我们开发人员还需要做一些额外的工作才能完全生成轮密钥。

为什么SSE不提供完整的AES密钥生成流程?

请参阅英特尔 AES-NI 白皮书中的 Key Expansion Using AESKEYGENASSIST (page 23)。他们指出该指令可以用作不同密钥大小的构建块:128/192/256。他们只展示了 128b 的示例,按照您的描述在每个 aeskeygenassist 指令之后通过函数调用完成额外的工作。

AESKEYGENASSIST 已经进行了微编码(例如,Skylake 上的 13 微指令与 AESDEC / AESENC (http://agner.org/optimize/) 中的 1 微指令相比),因此有不同的指令执行最后一个对于不同的密钥大小,几个不同的步骤不会使其 运行 比当前实施的方式快得多。

Skylake 每 12 个周期有 1 个 aeskeygenassist 吞吐量,但 Nehalem 每 2 个周期有 1 个,与 aesenc 相同。所以在 Nehalem,我猜他们确实主要在专用硬件中实现了它。这可能是解释的另一部分:更多的步骤将在第一代实现中采用更多的硬件,或者对该指令进行微编码(它可能不在 Nehalem 中)以使用更多的 uops 执行额外的步骤。

英特尔显然不认为密钥设置对性能至关重要,因为正如我所说,他们在 Nehalem 之后降低了 aeskeygenassist 的性能。 (即使是 Sandybridge 也对其进行了微编码,每 8 个时钟吞吐量 1 个。)


对不同的密钥大小使用不同的指令会占用更多的操作码。那时,Intel 还没有引入 VEX 前缀,所以在 AES 指令上花费更多的操作码 space 会减少未来扩展的空间。 (VEX 有大量编码 space 可用,仅对当前指令使用的现有强制性前缀组合使用几个多位代码。)