手工SHA-256,计算SHA-256初始单词

2024-02-13

我正在阅读出版物FIPS 180-4 https://csrc.nist.gov/csrc/media/publications/fips/180/4/final/documents/fips180-4-draft-aug2014.pdf并尝试自己实现 SHA-256。第 15 页,标题5.3.3 SHA-256我们对初始哈希值进行了初始化:

5.3.3 SHA-256

For SHA-256, the initial hash value, H(0), shall consist of the following eight 32-bit words, in hex:

H0 = 6a09e667
H1 = bb67ae85
H2 = 3c6ef372
H3 = a54ff53a
H4 = 510e527f
H5 = 9b05688c
H6 = 1f83d9ab
H7 = 5be0cd19

These words were obtained by taking the first thirty-two bits of the fractional parts of the 
square roots of the first eight prime numbers.

所以,我开始自己计算这些数字,然后我的问题出现了。根据维基百科:双精度浮点格式 https://en.wikipedia.org/wiki/Double-precision_floating-point_format以二进制表示的数字,小数部分由 0-51 位表示,指数部分由 52-62 位表示,符号部分由 63 位表示。因此,为了初始化初始哈希值,我们采用小数部分的前 32 位,即 20-51 位:

H0 = 6a09e667 (hex)
sqrt(2) = 1.4142135623730951 = [0][01111111111][01101010000010011110011001100111|11110011101111001101]
H0 = 01101010000010011110011001100111 (binary)
H0'= 01101010000010011110011001100111 (binary)
H0 == H0' ->  OK 
-------------------
H1 = bb67ae85 (hex)
sqrt(3) = 1.7320508075688772 = [0][01111111111][10111011011001111010111010000101|10000100110010101010]
H1 = 10111011011001111010111010000101 (binary)
H1'= 10111011011001111010111010000101 (binary)
H1 == H1' ->  OK 
-------------------
H2 = 3c6ef372 (hex)
sqrt(5) = 2.23606797749979 = [0][10000000000][00011110001101110111100110111001|01111111010010101000]
H2 = 00111100011011101111001101110010 (binary)
H2'= 00011110001101110111100110111001 (binary)
H2 != H2' ->  SHIFTED! 
-------------------
H3 = a54ff53a (hex)
sqrt(7) = 2.6457513110645907 = [0][10000000000][01010010101001111111101010011101|00101111100011101010]
H3 = 10100101010011111111010100111010 (binary)
H3'= 01010010101001111111101010011101 (binary)
H3 != H3' ->  SHIFTED! 
-------------------
H4 = 510e527f (hex)
sqrt(11) = 3.3166247903554 = [0][10000000000][10101000100001110010100100111111|11010110111100110100]
H4 = 01010001000011100101001001111111 (binary)
H4'= 10101000100001110010100100111111 (binary)
H4 != H4' ->  SHIFTED! 
-------------------
H5 = 9b05688c (hex)
sqrt(13) = 3.605551275463989 = [0][10000000000][11001101100000101011010001000110|00010101100111110011]
H5 = 10011011000001010110100010001100 (binary)
H5'= 11001101100000101011010001000110 (binary)
H5 != H5' ->  SHIFTED! 
-------------------
H6 = 1f83d9ab (hex)
sqrt(17) = 4.123105625617661 = [0][10000000001][00000111111000001111011001101010|11111110110100000111]
H6 = 00011111100000111101100110101011 (binary)
H6'= 00000111111000001111011001101010 (binary)
H6 != H6' ->  SHIFTED! 
-------------------
H7 = 5be0cd19 (hex)
sqrt(19) = 4.358898943540674 = [0][10000000001][00010110111110000011001101000110|01000100110111111001]
H7 = 01011011111000001100110100011001 (binary)
H7'= 00010110111110000011001101000110 (binary)
H7 != H7' ->  SHIFTED! 
-------------------

问题是为什么 H 的一些给定二进制表示FIPS 180-4 https://csrc.nist.gov/csrc/media/publications/fips/180/4/final/documents/fips180-4-draft-aug2014.pdf(似乎)以某种方式发生了变化,或者,我认为我正确地采用了小数部分,但如果没有 - 我做错了什么?

我写的代码如下:

package ru.iulgutlin.sha256;

import java.util.Arrays;
import java.util.Objects;

/**
 * Test
 *
 * @author Rail Iulgutlin 1/9/22
 */
public class Test {

    private static final long[] PRIMES = new long[64];

    /**
     * Given H values
     */
    private static final long h0 = 0x6a09e667L;
    private static final long h1 = 0xbb67ae85L;
    private static final long h2 = 0x3c6ef372L;
    private static final long h3 = 0xa54ff53aL;
    private static final long h4 = 0x510e527fL;
    private static final long h5 = 0x9b05688cL;
    private static final long h6 = 0x1f83d9abL;
    private static final long h7 = 0x5be0cd19L;
    private static final long[] h = {h0, h1, h2, h3, h4, h5, h6, h7};

    static {
        initPrimes();
    }

    public static void main(String[] args) {
        long[] s = new long[8];
        for (int i = 0; i < s.length; i++) {
            /**
             * Calculating my own H' values and comparing with given
             */
            double sqrt = Math.sqrt(PRIMES[i]);
            s[i] = firstFractionalParts(sqrt, 32);
            String h = binary(CustomSha256.h[i], 32); // h given binary string representation
            String h_ = binary(s[i], 32); // h' calculated binary string representation
            boolean eq = Objects.equals(h, h_);

            // print result pretty formatted
            print("    H" + i + " = " + Long.toHexString(CustomSha256.h[i]) + " (hex)");
            print("    sqrt(" + PRIMES[i] + ") = " + sqrt +
                    " = " + new StringBuilder(binary(Double.doubleToRawLongBits(sqrt), 64))
                    .insert(0, '[')
                    .insert(2, "][")
                    .insert(15, "][")
                    .insert(49, '|')
                    .insert(70, ']'));
            print("    H" + i + " = " + h + " (binary)");
            print("    H" + i + "'= " + h_ + " (binary)");
            print("    H" + i + (eq ? " == " : " != ") + "H" + i + "' -> " + (eq ? " OK " : " SHIFTED! "));
            print("    -------------------");
        }
    }

    /**
     * Returns first k bits of fractional part bits of d.
     * <p>
     * Example calling with d = 1.7320508075688772 and k = 32:
     * d = [0][01111111111][10111011011001111010111010000101|10000100110010101010]
     * Returns:
     * [10111011011001111010111010000101]
     *
     * @param d double number
     * @param k number of bits
     * @return first k bits of fractional part bits of d
     */
    private static long firstFractionalParts(double d, int k) {
        // first 12 bits are not fractional
        // Example: given d = [0][01111111111][10111011011001111010111010000101][10000100110010101010] and k = 32
        // first rotate bits to right so that first bit we need will stay in the rightest position
        // we get [10000100110010101010][0][01111111111][10111011011001111010111010000101]
        // second cut everything redundant and return
        // [00000000000000000000][0][00000000000][10111011011001111010111010000101]
        return cut(rotate(Double.doubleToRawLongBits(d), Double.SIZE - 12 - k), k);
    }

    /**
     * Cuts(turns to 0) every bit of b except right k bits.
     * <p>
     * Example calling with b = 10111011001 = 1497 and k = 4
     * Returns 00000001001 (only 4 right bits remain)
     *
     * @param b bits
     * @param k nuber of bits to remain
     * @return cutted bits
     */
    private static long cut(long b, int k) {
        return b & (-1L >>> (Long.SIZE - k));
    }

    /**
     * Rotates bits right to a given k positions within 64 bits.
     * Example calling with b = 0000000000000000000000000000000000000000000000000000010111011001 = 1497 and k = 3
     * Returns 0010000000000000000000000000000000000000000000000000000010111011 (rotated right to 3 positions)
     *
     * @param bits bits to rotate
     * @param k positions
     * @return rotated value
     */
    private static long rotate(long bits, int k) {
        return ((bits >>> k) | (bits << (Long.SIZE - k)));
    }

    private static String binary(long b, int k) {
        return String.format("%" + k + "s", Long.toBinaryString(b & (-1L >>> (Long.SIZE - k)))).replace(' ', '0');
    }

    private static void initPrimes() {
        int i = 0;
        long k = 0;
        while (i < 64) {
            if (isPrime(k)) {
                PRIMES[i] = k;
                i++;
            }
            k++;
        }
        print("PRIMES : " + Arrays.toString(PRIMES));
    }

    private static boolean isPrime(long a) {
        if (a < 2) return false;
        if (a == 2) return true;
        if (a % 2 == 0) return false;
        for (long i = 3; i * i <= a; i += 2)
            if (a % i == 0) return false;
        return true;
    }

    private static void print(Object o) {
        System.out.println(o);
    }
}

√2 = 1.4142135623730951 = 0.4142135623730951  //1 is neglected
H0 = 0.4142135623730951 * 2^32
   = 1779033703
   = 0x6A09E667 //hex(1779033703)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手工SHA-256,计算SHA-256初始单词 的相关文章

随机推荐