如何生成SHA2常数序列

该博客介绍了如何计算质数立方根,并基于此生成SHA-2算法中的4字节和8字节常量。C语言代码用于生成SHA-256的4字节常数,而Python代码借助gmpy2库生成SHA-512的8字节常量。讨论了IEEE754浮点数表示法在这一过程中的作用。
摘要由CSDN通过智能技术生成

SHA-256算法中,使用64个4字节整型常量。这些常量表示前64个质数立方根小数部分的前32位。

要取立方根小数部分,需要了解double类型(8字节==64位)的内存布局,对应标准IEEE 754,以下为double类型64位从高到低的解释

  • 1 bit 符号位 S
  • 11 bit 阶码位 E
  • 52 bit 小数位 M

转为十进制的公式:

( − 1 ) S × 2 E − 1023 × [ 1 + ∑ i = 1 52 ( M i × 2 − i ) ] (-1)^S \times 2^{E-1023} \times [1+\sum_{i=1}^{52}(M_i \times 2^{-i}) ] (1)S×2E1023×[1+i=152(Mi×2i)]

以质数2为例,它的小数部分如下:

0.259921049894873 ≈ 4 × 1 6 − 1 + 2 × 1 6 − 2 + 8 × 1 6 − 3 + . . . 0.259921049894873 \approx 4 \times 16 ^{-1} + 2 \times 16 ^{-2} + 8 \times 16 ^{-3} + ... 0.2599210498948734×161+2×162+8×163+...

对应的十六进制为0x428a2f98。

需要注意的则是阶码部分,转换为十进值是乘以2的次方,反过来则是除以2的次方(右移)。

C

#include <stdio.h>
#include <math.h>
int main(int argc, char* argv[])
{


	int arrPrimeNum[80] = {0};
	int i = 0, j = 0;
	double dNum = 0;
	char bFlag = 0;

	int nCountPrime = 0;
	int nNum = 1;
	unsigned int nTmp = 0;
	long long int llNum = 0;

	while (80 != nCountPrime)
	{
		nNum += 1;
		bFlag |= 1;

		j = sqrt(nNum);
		for (i = 2; i <= j; ++i)
		{
			if (nNum % i == 0)
			{
				bFlag &= 0;
				break;
			}
		}
		if (bFlag)
		{
			arrPrimeNum[nCountPrime++] = nNum;
		}
	}
	
	for (i = 0; i < nCountPrime; ++i)
	{
		dNum = exp(log(arrPrimeNum[i]) / 3);
		llNum = *(long long*)&dNum;

		/*
		 IEEE 754
			fractional part: 0-51 from left to right
		SHA-256 need 32-bit word
				>> (52-4*8) == 20
		SHA-512 need 64-bit word
			Big integer library is needed to implement
		eg. 
			arrPrimeNum[0] == 2
			step code == b01111111111-1023 == 0
			shift right (20 - 0)
				0 01111111111 01000010 10001010 00101111 10011000 11010111 00101000 1011
							  01000010 10001010 00101111 10011000
			arrPrimeNum[4] == 11
			step code == b10000000000-1023 == 1
			shift right (20 - 1)
				0 10000000000 00011100 10101011 01100001 00101101 11111001 10100100 0110
							   0011100 10101011 01100001 00101101 1
		*/

		nTmp = 20 - (((llNum >> 52) & 0x7FF) - 0x3FF );
		printf("0x%08llx, ", (llNum >> nTmp) & 0xFFFFFFFF);

		if ((i + 1) % 8 == 0)
		{
	 		printf("\n");
		}
	 
	}
	getchar();
	return 0;
}

python

上面用c语言生成了sha-256的4字节常数序列,而sha-512的常数序列与之类似,使用80个8字节整型常量,这些常量表示前80个质数立方根小数部分的前64位。

小数部分取64位,就不能利用double类型实现了,因为double类型一共就64位,根据IEEE 754,小数部分只有52位。所以需要借助大数库来生成sha-512的常数序列,这里借助gmpy库来实现。

import gmpy2
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))
    strRet = "{0:1a}".format(floor(frac_part*(16**hex_chars)))
    # 0xc.19bf174p+28
    strRet = strRet[2:]
    strRet = strRet.replace(".","")
    # c19bf174p+28
    strRet = strRet[:strRet.index("p+")]
    # c19bf174
    while(len(strRet) < 8):
        strRet = "0" + strRet
    return strRet;


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

# SHA-256 constants
# 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), end=" ")

# SHA-512 constants
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), end=" ")

参考资料

https://crypto.stackexchange.com/questions/41496/how-to-generate-the-sha-2-constants

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值