4
$\begingroup$

The SHA spec states - eg, in the case of SHA-224 and SHA-256 - that the constants "represent the first 32-bits of the fractional parts of the cube roots of the first 64 primes". How are these values "represented"? Beginning with a prime number, and ending with the hex constant, what is the correct sequence of steps to generate all of the constants as provided in the spec?

$\endgroup$
4
$\begingroup$

It's exactly how it sounds. Note: 428a2f98 when interpreted as a hexadecimal fraction has the value of 4/16 + 2/(16^2) + 8/(16^3) + 10/(16^4) + ... which is approximately equal to 0.2599210496991873, so when you add back the non-fractional part you get 1.2599210496991873 which is the cube-root of the first prime number (2).

In python:

In [1]: 1+sum([int(c,16)/(16.**(i+1)) for (i,c) in enumerate('428a2f98')])
Out[1]: 1.2599210496991873

In [2]: 2**(1/3.)
Out[2]: 1.2599210498948732

To generate the constants you can the gmpy2 python library with the following code:

from gmpy2 import mpfr, floor, next_prime

def convert_primes_cube_fractional_part_to_hex_constant(prime, hex_chars=8):
    """
    Note if you want the first 8 decimal (base=10) digits of a number,
    you multiply the fractional part by 10**8 and then look at the integer part 
    In this case we want first 8 hex digits, so multiply fractional part by 16**8
    and then look at integer part (and return in hexadecimal).
    """
    cube_root = mpfr(prime)**(1/mpfr(3))
    frac_part = cube_root - floor(cube_root)
    format_str = '%%0%dx' % hex_chars  
    # format_str will be '%08x' if hex_chars=8 so always emits 
    # 8 zero-padded hex digits 
    return format_str % floor(frac_part*(16**hex_chars))

def generate_n_primes(n=64):
    p = 2
    i = 0
    while i < n:
        yield p
        p = next_prime(p)
        i += 1

After defining those functions you can run, the following to recreate the table:

>>> for i,p in enumerate(generate_n_primes(64)):
        if i % 8 == 0:
            print ""
        print convert_primes_cube_fractional_part_to_hex_constant(p, hex_chars=8),


428a2f98 71374491 b5c0fbcf e9b5dba5 3956c25b 59f111f1 923f82a4 ab1c5ed5 
d807aa98 12835b01 243185be 550c7dc3 72be5d74 80deb1fe 9bdc06a7 c19bf174 
e49b69c1 efbe4786 0fc19dc6 240ca1cc 2de92c6f 4a7484aa 5cb0a9dc 76f988da 
983e5152 a831c66d b00327c8 bf597fc7 c6e00bf3 d5a79147 06ca6351 14292967 
27b70a85 2e1b2138 4d2c6dfc 53380d13 650a7354 766a0abb 81c2c92e 92722c85 
a2bfe8a1 a81a664b c24b8b70 c76c51a3 d192e819 d6990624 f40e3585 106aa070 
19a4c116 1e376c08 2748774c 34b0bcb5 391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3 
748f82ee 78a5636f 84c87814 8cc70208 90befffa a4506ceb bef9a3f7 c67178f2

Note this exactly matches the table in the NIST publication.

You can generate the other SHA-512 constants with the following code. Note you first have to increase the multiple precision floating point math in gmpy2 to ~100 digits from the default 53 digits, or you'll find the last few hexdigits are always 0 due to loss of precision.

>>> gmpy2.get_context().precision=100
>>> for i,p in enumerate(generate_n_primes(80)):
        if i % 4 == 0:
            print ""
        print convert_primes_cube_fractional_part_to_hex_constant(p, hex_chars=16),
| improve this answer | |
$\endgroup$
  • $\begingroup$ Thank you! So, multiply the fractional part of the decimal by 16^8, then convert the resultant decimal to hex. Eg, the cube root of 2 = 1.259921049699. 0.259921049699*(16^8) = 1,116,352,408 = 0x428a2f98. $\endgroup$ – Professor Hantzen Nov 15 '16 at 9:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.