SHA-3 (Keccak) 海绵结构中的 ι (Iota) 步骤详解
你好!我将为你讲解 SHA-3 哈希算法(核心是 Keccak 海绵结构)中,轮函数 Keccak-f 的最后一个步骤——ι 步骤。这个步骤虽然看起来简单,但其设计精巧,对整个算法的非线性和安全性有至关重要的作用。我们将从问题背景、核心概念,再到具体的计算过程,循序渐进地进行解析。
题目背景
SHA-3 是美国国家标准与技术研究院(NIST)在 2012 年通过哈希算法竞赛选出的新一代标准哈希算法,其核心是 Keccak 哈希函数。Keccak 采用“海绵结构”来处理任意长度的输入,并输出指定长度的哈希值。而海绵结构中的“吸收”和“挤压”阶段,都反复调用一个固定的置换函数,称为 Keccak-f。
Keccak-f 函数对内部状态(一个三维的比特数组)进行多轮(SHA-3标准为24轮)的混淆和扩散。每一轮包含5个步骤,按顺序为:
- θ (Theta): 提供列之间的扩散。
- ρ (Rho): 提供行内的位旋转扩散。
- π (Pi): 提供行与行之间的置换。
- χ (Chi): 提供非线性混淆,是主要的非线性来源。
- ι (Iota): 为每一轮添加一个独特的轮常数,打破轮函数内部的对称性,并确保每轮都不同。
我们今天的主角就是最后一步:ι 步骤。
解题过程
第一步:理解 Keccak 的内部状态表示
在深入 ι 步骤之前,必须理解 Keccak 操作的“数据块”是什么样的。
Keccak 的内部状态被表示为一个三维的比特数组,其大小为 5×5×w。其中:
- w 是“字长”,即每个“车道”的比特数。在 SHA-3 标准中,使用的是 Keccak-f[1600],即总状态大小为 1600 比特。因为 5×5×w = 1600,所以 w = 64 比特。
- 我们可以把这个状态想象成一个 5 行、5 列的“平面”,而每一“格”不是一个简单的比特,而是一个“车道”——一个长度为 w=64 比特的向量,从垂直于平面的方向延伸出去。所以状态是三维的。
状态中的任何一个比特可以用三个坐标 (x, y, z) 表示:
- x (0到4): 列坐标
- y (0到4): 行坐标
- z (0到63): 在车道内的深度坐标(比特位置)
ι 步骤的操作对象是 x=0, y=0 的这一条车道,即最左上角的那条 64 比特长的车道。
第二步:ι 步骤的目的
在每轮轮函数中,前四步(θ, ρ, π, χ)都是完全确定的、与轮数无关的线性或非线性变换。如果仅仅重复这些步骤,整个置换会呈现很强的代数结构,可能导致对称性攻击或固定点(输出等于输入的状态)容易被找到。
ι 步骤的核心作用就是打破这种对称性:
- 破坏自相似性: 通过为每一轮添加一个不同的常数,使得第 1 轮和第 2 轮的变换完全不同,防止攻击者利用轮函数的自相似性进行分析。
- 消除弱轮: 没有 ι 步骤,某些特定输入(如全0)在经过某些步骤(如 χ)时,其非线性效应可能很弱。加入精心设计的轮常数可以避免这种弱轮情况。
- 增加代数复杂度: 即使攻击者能对前几步建立简单的代数方程,ι 步骤引入的常数也会使这些方程复杂化,难以求解。
简单来说,ι 步骤就像是给每一轮的“料理”撒上一点点不同的、独特的“调味料”,确保24道“料理”味道都不同,且没有一道是寡淡无味的。
第三步:ι 步骤的计算公式
ι 步骤的操作非常简单,它是一个位异或(XOR)操作:
A[x, y, z] = A[x, y, z] ⊕ RC[i_r, z]
让我们分解这个公式:
- A[x, y, z]: 这是内部状态数组。它存储了当前所有 5×5×64 = 1600 个比特。
- ⊕: 表示按位异或运算。在二进制中,0⊕0=0, 0⊕1=1, 1⊕0=1, 1⊕1=0。
- RC[i_r, z]: 这就是“轮常数”。它只作用于特定车道 (x=0, y=0) 的特定深度 z 位置的比特。如果 RC[i_r, z] = 1,则该位置的比特就翻转(0变1,1变0);如果为0,则保持不变。
关键点:
- 坐标限定: 这个操作只对坐标
(x=0, y=0)的整条车道(即64个比特位)进行。对于 x 和 y 不为 (0,0) 的所有比特,ι 步骤不做任何改变。 - 轮数依赖: 常数
RC[i_r, z]的值取决于两个参数:i_r: 当前的轮索引。Keccak-f[1600] 有 24 轮,所以 i_r 从 0 到 23。z: 车道内的比特位置索引(0 到 63)。
这意味着,在24轮中的每一轮,都会有一个长度为64比特的、独一无二的“轮常数掩码”被 XOR 到最左上角 (0,0) 的车道上。
第四步:轮常数 RC 的生成规则
轮常数 RC 的设计并非随意,而是遵循一个确定性的、简洁的线性反馈移位寄存器(LFSR)规则生成的。这样设计是为了:
- 确定性: 任何人都能复现。
- 简洁: 不需要存储24×64个常数,只需一个简单的生成算法。
- 足够随机: 满足密码学所需的“看似随机”的特性。
以下是生成规则(你无需记忆,但可以理解其逻辑):
- 我们定义一组“轮常数比特”
rc[t],其中 t 从 0 开始。rc[t]是一个单独的比特 (0 或 1)。 rc[t]由一个 8 比特的 LFSR 生成,其生成多项式为x^8 + x^6 + x^5 + x^4 + 1。- 初始化 LFSR 寄存器状态
rc[0…7] = 10000000(二进制,rc[0]=1,其余为0)。 - 对于每个新的 t,寄存器按 LFSR 规则更新一次,最低位的值就是新的
rc[t]。 - 生成了足够的
rc[t]后,对于第i_r轮,其轮常数RC[i_r]是一个64比特的字。这个字的第z个比特是否为1,由以下规则判断:- 对于所有满足
(7^m) mod 255 = 1的整数 m,如果存在某个整数 j 使得z = 2^j - 1,并且rc[j + 7*i_r] = 1,那么RC[i_r, z] = 1。 - 对于所有其他位置 z,
RC[i_r, z] = 0。
- 对于所有满足
一个更简单的理解方式是:在24轮中,只有很少的几个特定 z 位置(如 0, 1, 3, 7, 15, 31, 63等)的比特可能被设为1。每一轮的轮常数就是由这些位置上的、由 LFSR 生成的比特 rc[t] 组合而成的一个“稀疏”的64比特掩码。
例如,前两轮的轮常数(以16进制表示,作用于64位车道)是:
- 轮 0 (i_r=0):
RC[0] = 0x0000000000000001 - 轮 1 (i_r=1):
RC[1] = 0x0000000000008082
你可以看到,只有最低的几个比特位是1,其余都是0。这正是“稀疏”的含义。
第五步:实际计算示例
让我们以第0轮(i_r=0)为例,手动计算它对状态的影响:
假设在 ι 步骤之前,经过 θ, ρ, π, χ 步骤后,状态中左上角车道 (x=0, y=0) 的64个比特是:
A[0, 0] = 0x0123456789ABCDEF (这是一个64位的十六进制数,仅为举例)。
- 查表: 已知第0轮的轮常数
RC[0] = 0x0000000000000001。这意味着只有在 z=0 这个比特位置(即最低有效位,LSB)的常数是1,其他63个位置都是0。 - 执行操作: ι 步骤要求计算
A[0,0] ⊕ RC[0]。A[0,0]的二进制最低位是F的二进制表示1111的最低位,即 1。RC[0]在最低位是 1。- 1 ⊕ 1 = 0。
- 得到结果: 因此,新状态
A'[0,0]的值变为0x0123456789ABCDE?,其中?是E(1110) 的最低三位 110 与 RC 的0进行异或,还是110,所以是E。最终结果是A'[0,0] = 0x0123456789ABCDEE。我们只是翻转了最低位。
这个例子展示了 ι 步骤如何通过一个微小的、与轮数相关的改动,来影响整个状态。在后续的轮函数迭代中,这个微小的改变会被 θ, ρ, π, χ 等步骤迅速扩散到状态的每一个角落。
总结
ι 步骤 是 Keccak-f 轮函数中看似最简单的一步,但其密码学意义重大:
- 操作简单: 仅对内部状态的特定车道 (0,0) 与一个轮常数进行按位异或。
- 目标明确: 打破轮函数的对称性和自相似性,消除潜在的弱轮,增加代数攻击的难度。
- 常数生成: 轮常数由简洁的 LFSR 确定性地生成,每轮不同且稀疏,是算法设计者精心挑选的“魔力常数”。
正是这五个步骤(θ, ρ, π, χ, ι)的精心组合与多轮迭代,共同赋予了 SHA-3 (Keccak) 强大的混淆、扩散和非线性特性,使其能够抵抗已知的各种密码学攻击,成为值得信赖的新一代哈希标准。