使用-pg与优化选项生成SHA3-512哈希时出现异常现象求助
问题分析与修复方案
核心问题根源
你的程序在同时启用-pg(gprof性能分析)和-O1/-O2/-O3优化时出现异常,本质是未定义行为在特定编译选项组合下触发了巧合的错误结果,具体问题点如下:
1. 未初始化的res_size参数导致哈希计算异常
tomcrypt的hash_memory函数要求最后一个参数outlen在调用前必须设置为输出缓冲区的大小(SHA3-512输出为64字节)。你的代码中unsigned long res_size;未初始化,传递给hash_memory后会引入随机值,在优化+gprof的环境下,这个随机值刚好导致哈希输出的前8字节被错误置零。
2. 哈希数据拼接逻辑完全错误
你设计的是随机字符串+nonce的组合哈希,但代码中把nonce写到了string[11...]的位置,覆盖了随机字符串的中间部分,并且哈希长度30+nonce_len会包含string[30...]的未初始化栈垃圾数据。在特定编译环境下,这些垃圾数据恰好让哈希前8位全零,导致循环直接退出。
3. 随机数生成的冗余与错误
randstring函数每次调用都执行srand(time(NULL)),如果函数被多次调用(当前代码仅调用一次,但属于不良设计),会导致随机数重复;同时rand() % 255生成的是0-254的值,无法覆盖完整的字节范围(应该用rand() % 256)。
修复后的代码
#include <tomcrypt.h> #include <string.h> #include <time.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> unsigned char* randstring(size_t length) { unsigned char* randomString = NULL; if (length) { randomString = malloc(sizeof(unsigned char) * length); if (randomString) { for (size_t n = 0; n < length; n++) { int key = rand() % 256; // 生成0-255的完整字节值 randomString[n] = (unsigned char)key; } } } return randomString; } void find_nonce(int zeroes, int* nonce_ptr, unsigned char* returner, int hash_idx) { unsigned char string[40]; memset(string, 0, sizeof(string)); // 初始化栈数组,避免垃圾数据 unsigned char* rand_string = randstring(30); memcpy(string, rand_string, 30); free(rand_string); int nonce = 0; bool res_bool = false; unsigned char res[64]; unsigned long res_size = sizeof(res); // 正确设置输出缓冲区大小 char nonce_str[11]; while (!res_bool) { sprintf(nonce_str, "%d", nonce); int nonce_len = strlen(nonce_str); // 将nonce追加到随机字符串末尾(string[30...]位置) memcpy(&string[30], nonce_str, nonce_len); // 计算哈希:随机字符串(30字节) + nonce字符串(nonce_len字节) hash_memory(hash_idx, string, 30 + nonce_len, res, &res_size); // 检查前导零数量 res_bool = true; for (int i = 0; i < zeroes; i++) { if (res[i] != 0) { res_bool = false; break; } } nonce++; } *nonce_ptr = nonce; memcpy(returner, res, sizeof(res)); } int main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "Usage: %s <number_of_zeroes>\n", argv[0]); return 1; } int zeroes = atoi(argv[argc - 1]); if (zeroes < 1 || zeroes > 64) { fprintf(stderr, "Zeroes must be between 1 and 64\n"); return 1; } // 只注册一次哈希算法 if (register_hash(&sha3_512_desc) == -1) { fprintf(stderr, "Error registering SHA3-512.\n"); return 1; } int hash_idx = find_hash("sha3-512"); if (hash_idx == -1) { fprintf(stderr, "Invalid hash name!\n"); return 1; } // 初始化随机数生成器(只执行一次) srand(time(NULL)); int nonce; unsigned char hash[64]; clock_t start, end; double cpu_time_used; start = clock(); find_nonce(zeroes, &nonce, hash, hash_idx); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("Hash was "); for (int i = 0; i < 64; i++) { printf("%d ", (int)hash[i]); } printf("\nNonce to get the hash was %d\nIt took %f seconds to calculate\n", nonce, cpu_time_used); return 0; }
关键修复点说明
- 正确初始化
res_size:调用hash_memory前设置res_size = sizeof(res),确保函数知道输出缓冲区的大小。 - 修正哈希拼接逻辑:将nonce追加到随机字符串的末尾(
string[30...]),确保哈希的是随机字符串+nonce的合法组合,避免读取未初始化的栈数据。 - 初始化栈数组:用
memset初始化string数组,消除垃圾数据的影响。 - 优化随机数生成:将
srand(time(NULL))移到main函数只执行一次,修正rand() % 256以覆盖完整字节范围。 - 哈希算法注册逻辑优化:将
register_hash和find_hash移到main函数,只执行一次,避免重复注册的潜在问题。 - 增加参数校验:添加命令行参数的合法性检查,提升程序健壮性。
编译说明
修复后的代码无论是否启用-pg和优化选项,都会正常工作:
- 普通编译:
gcc -o hashcash hashcash.c -ltomcrypt - 带gprof的优化编译:
gcc -pg -O2 -o hashcash hashcash.c -ltomcrypt
内容的提问来源于stack exchange,提问作者drake14w
相关产品推荐
相关产品推荐

