You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SHA-256初始哈希值计算疑问:为何部分FIPS 180-4给定值与自行计算值存在偏移?

Troubleshooting SHA-256 Initial Hash Values Calculation Mismatch

Let's break down why your calculated initial hash values (H2-H7) don't match the FIPS 180-4 specification, and fix the issue in your Java code.

The Root Cause

Your approach to extracting the fractional bits is incorrect because you're not accounting for how double-precision floating-point numbers represent values. For numbers greater than or equal to 1 (like the square roots of primes we're using here), double-precision format stores the value as:

  • 1 sign bit
  • 11 exponent bits
  • 52 mantissa bits (which represent the fractional part of 1.mantissa, not just the raw fractional part of the number)

The key mistake: you're trying to extract bits directly from the raw long representation without including the implicit leading 1 in the mantissa, and your bit-shifting logic is misaligned with how the fractional part maps to the mantissa.

Correct Approach to Extract the First 32 Fractional Bits

The initial SHA-256 hash values are derived from the first 32 bits of the fractional part of the square root of the first 8 primes. To get this correctly:

  1. Take the square root of the prime.
  2. Subtract the integer part to isolate the pure fractional value (e.g., sqrt(5) = 2.23606... → fractional part is 0.23606...).
  3. Multiply this fractional value by 2^32 and take the integer result (this gives you the first 32 bits of the fractional part as a 32-bit integer).

Alternatively, using bit manipulation (more efficient):

  1. Convert the double value to its raw 64-bit long representation.
  2. Extract the 52-bit mantissa.
  3. Add the implicit leading 1 to form the full 53-bit significand (1.mantissa).
  4. Shift right to keep only the top 32 bits of the fractional part (since the fractional part is 0.mantissa, the first 32 bits correspond to the top 32 bits of the mantissa).

Fixed Java Code

Here's how to modify your firstFractionalParts method to get the correct values:

private static long firstFractionalParts(double d, int k) {
    // Option 1: Mathematical approach (simpler to understand)
    double fractional = d - Math.floor(d);
    return (long) (fractional * (1L << k));

    // Option 2: Bit manipulation approach (more efficient)
    /*
    long rawBits = Double.doubleToRawLongBits(d);
    long mantissa = rawBits & 0x000FFFFFFFFFFFFFL; // Extract 52-bit mantissa
    long fullSignificand = (1L << 52) | mantissa; // Add implicit leading 1
    return fullSignificand >>> (53 - k); // Keep top 32 bits of the fractional part
    */
}

Why This Works

Let's verify with H2 (prime = 5):

  • sqrt(5) ≈ 2.2360679775
  • Fractional part: 0.2360679775
  • Multiply by 2^32 (4294967296): 0.2360679775 * 4294967296 ≈ 1013904242
  • Convert to hex: 0x3c6ef372 → which matches the FIPS 180-4 H2 value exactly.

Your original code's bit-shifting logic was rotating and cutting bits incorrectly, leading to offset values. The fixed methods correctly isolate and extract the fractional bits as required by the SHA-256 specification.

Bonus: Verify Your Prime List

Make sure your PRIMES array starts with the first 8 primes: [2, 3, 5, 7, 11, 13, 17, 19]. Your initPrimes function should generate this correctly, but double-checking avoids another potential source of mismatch.

内容的提问来源于stack exchange,提问作者Rail Yulgutlin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 02:52:51