SHA-256 哈希算法的常量生成与初始化过程详解
题目描述
在 SHA-256 哈希算法中,算法初始化时需要一组固定的 64 个常量 K(称为“轮常量”),以及 8 个初始哈希值 H⁽⁰⁾。请详细解释这 64 个轮常量是如何生成的,以及初始哈希值是如何确定的,并说明它们的作用。
解题过程
SHA-256 是美国国家标准与技术研究院(NIST)设计的 SHA-2 系列算法之一,输出 256 位哈希值。其核心是 64 轮的压缩函数计算,每轮使用一个独特的 32 位轮常量 Kₜ。初始化哈希值 H⁽⁰⁾ 是固定的 8 个 32 位常数。这些常数并非随意设置,而是来自数学推导,确保算法无后门、具有良好随机性。
第一步:理解 SHA-256 算法流程概述
SHA-256 对输入消息进行填充、分块(每块 512 位),然后对每个消息块执行压缩函数。压缩函数中:
- 从当前消息块中导出一个 64 个 32 位字的扩展消息序列 W₀, W₁, …, W₆₃。
- 初始化 8 个工作变量 a, b, c, d, e, f, g, h,初始值为当前的哈希中间值 H⁽ⁱ⁾。
- 进行 64 轮迭代,每轮 t(0 ≤ t ≤ 63)中:
- 计算两个中间值 T₁ 和 T₂。
- 更新工作变量。
- 每轮会加一个轮常量 Kₜ,用于消除输入数据的规律性,增强混淆。
初始 H⁽⁰⁾ 是算法第一次执行压缩函数前的“起点”。
第二步:轮常量 Kₜ 的生成方法
SHA-256 的 64 个轮常量 K₀, K₁, …, K₆₃ 来自前 64 个素数(2, 3, 5, 7, 11, …)的立方根的小数部分前 32 位。
具体计算步骤:
- 取前 64 个素数 p = 2, 3, 5, 7, 11, 13, …, 311。
- 对每个素数 p,计算其立方根 ³√p。
- 取 ³√p 的小数部分(即去掉整数部分),得到一个小数 0.xxxxx…
- 将该小数转换为二进制小数,取前 32 位二进制数。
- 将这 32 位二进制数转换为十六进制,即为 Kₜ。
数学公式表达:
Kₜ = floor(2³² × fractional_part(³√pₜ)),其中 pₜ 是第 t 个素数(t 从 0 开始)。
为什么用素数立方根?
- 立方根是数学常数,可公开验证,不存在故意设计的后门。
- 素数序列确保每个 Kₜ 之间无明显关联。
- 小数部分在二进制下表现类似随机数,为轮函数提供非线性来源。
示例:
-
第一个素数 p₀ = 2,³√2 ≈ 1.2599210498948732,小数部分 0.2599210498948732。
乘以 2³² 得 1116352408.910…,取整 1116352408(十六进制 0x428a2f98)。
所以 K₀ = 0x428a2f98。 -
第二个素数 p₁ = 3,³√3 ≈ 1.4422495703074083,小数部分 0.4422495703074083。
得 K₁ = 0x71374491。
(完整 64 个常量在标准文档中已列,无需重新计算。)
第三步:初始哈希值 H⁽⁰⁾ 的确定
SHA-256 的初始哈希值是 8 个 32 位常数,记为 H₀⁽⁰⁾ 到 H₇⁽⁰⁾。它们来自前 8 个素数的平方根的小数部分前 32 位。
计算步骤:
- 取前 8 个素数:2, 3, 5, 7, 11, 13, 17, 19。
- 对每个素数 q,计算其平方根 √q。
- 取小数部分,转换为二进制后取前 32 位,再转十六进制。
公式:Hₐ⁽⁰⁾ = floor(2³² × fractional_part(√qₐ)),a = 0…7。
具体值:
- q₀ = 2 → √2 ≈ 1.4142135623 → 小数 0.4142135623 → H₀⁽⁰⁾ = 0x6a09e667
- q₁ = 3 → √3 ≈ 1.7320508075 → 小数 0.7320508075 → H₁⁽⁰⁾ = 0xbb67ae85
- q₂ = 5 → √5 ≈ 2.2360679774 → 小数 0.2360679774 → H₂⁽⁰⁾ = 0x3c6ef372
- q₃ = 7 → √7 ≈ 2.6457513110 → 小数 0.6457513110 → H₃⁽⁰⁾ = 0xa54ff53a
- q₄ = 11 → √11 ≈ 3.3166247903 → 小数 0.3166247903 → H₄⁽⁰⁾ = 0x510e527f
- q₅ = 13 → √13 ≈ 3.6055512754 → 小数 0.6055512754 → H₅⁽⁰⁾ = 0x9b05688c
- q₆ = 17 → √17 ≈ 4.1231056256 → 小数 0.1231056256 → H₆⁽⁰⁾ = 0x1f83d9ab
- q₇ = 19 → √19 ≈ 4.3588989435 → 小数 0.3588989435 → H₇⁽⁰⁾ = 0x5be0cd19
这些值是固定的,所有 SHA-256 计算都从它们开始。
第四步:常量的作用
-
轮常量 Kₜ 的作用:
- 在压缩函数每轮中与扩展消息字 Wₜ 一起参与运算。
- 提供每轮的“随机”常数,打破输入数据的对称性,防止固定点攻击。
- 如果没有 Kₜ,输入消息中的规律可能导致哈希输出出现规律,降低抗碰撞性。
-
初始哈希值 H⁽⁰⁾ 的作用:
- 作为哈希计算的初始状态(链接变量)。
- 由于来自无理数的平方根,可视为“无偏”的起始点,避免从全零开始可能引入的弱点。
- 不同 SHA-2 变体(如 SHA-224、SHA-512)使用不同的初始值,以此区分输出长度。
总结
SHA-256 的轮常量和初始哈希值均通过公开的数学常数(素数平方根或立方根的小数部分)衍生,确保可验证性和伪随机性。它们为算法提供了初始状态和每轮的非线性添加,是 SHA-256 具备强抗碰撞性的基础设计之一。实际实现时,这些值以常量数组形式预置,无需每次计算。