I decided to make a program to find a sha3-512 hash with a certain number of zeroes at the start (like hashcash). It was working fine in my initial tests, so i decided to profile it with gprof to see if I could make it faster. After I had compiled with -pg and run it, I though i should go buy a lotto ticket. On the very first nonce I got a hash with 8 zeroes. However, I ran it again and I again got a number with 8 zeroes at the start. In fact, there were many discernible patterns in the hashes. After a few tests, I found that this only happened if I compiled with -pg and one of -O1, -O2, and -O3.
Here is the program
#include <tomcrypt.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#include <stdio.h>
unsigned char* randstring(size_t length) {
srand(time(NULL));
unsigned char* randomString = NULL;
if (length) {
randomString = malloc(sizeof(char) * (length));
if (randomString) {
for (int n = 0; n < length; n++) {
int key = rand() % 255;
randomString[n] = (unsigned char)key;
}
}
}
return randomString;
}
void find_nonce(int zeroes, int* nonce_ptr, unsigned char* returner) {
unsigned char string[40];
unsigned char* rand_string = randstring(30);
memcpy(string, rand_string, 30);
free(rand_string);
//string is longer than rand_string because i need romm to put the nonce in
int nonce = 0;
int idx;
if (register_hash(&sha3_512_desc) == -1) {
printf("Error registering SHA3-512.\n");
exit(1);
}
idx = find_hash("sha3-512");
if (idx == -1) {
printf("Invalid hash name!\n");
exit(1);
}
int res_bool = false;
unsigned char res[64];
unsigned long res_size;
char nonce_str[11];
int nonce_len = 0;
while (!res_bool) {
//Put the nonce into a string
sprintf(nonce_str, "%d", nonce);
//Put the nonce string into the string as an unsigned char (hash_memory takes an unsigned char)
for (int i = 0, j = 11;; ++i, ++j) {
if (nonce_str[i] == '\0') {
break;
}
string[j] = (unsigned char)nonce_str[i];
nonce_len++;
}
//Hash it
hash_memory(idx, string, 30+nonce_len, res, &res_size);
nonce_len = 0;
//Check if the string has a sufficient number of zeroes at the start
res_bool = true;
for (int i = 0; i < zeroes; i++) {
if ((int)res[i] != 0) {
res_bool = false;
break;
}
}
nonce++;
}
*nonce_ptr = nonce;
for (int i = 0; i < 64; i++) {
returner[i] = res[i];
}
}
int main(int argc, char** argv) {
//Getting command-line arguments
int zeroes = atoi(argv[argc - 1]);
int nonce;
unsigned char hash[64];
//Timing the execution
clock_t start, end;
double cpu_time_used;
start = clock();
find_nonce(zeroes, &nonce, hash);
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
//Printing the output to the screen
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;
}
And here is an example output from five tests:
Hash was 0 0 0 0 0 0 0 0 6 203 85 177 228 127 0 0 192 128 164 212 252 127 0 0 129 219 85 177 228 127 0 0 0 235 105 177 228 127 0 0 144 128 164 212 252 127 0 0 2 0 0 0 0 0 0 0 48 130 164 212 252 127 0 0
Nonce to get the hash was 1
It took 0.000000 seconds to calculate
Hash was 0 0 0 0 0 0 0 0 6 203 214 123 135 127 0 0 64 216 207 126 253 127 0 0 129 219 214 123 135 127 0 0 0 235 234 123 135 127 0 0 16 216 207 126 253 127 0 0 2 0 0 0 0 0 0 0 176 217 207 126 253 127 0 0
Nonce to get the hash was 1
It took 0.000000 seconds to calculate
Hash was 0 0 0 0 0 0 0 0 6 123 219 55 192 127 0 0 144 108 17 232 252 127 0 0 129 139 219 55 192 127 0 0 0 155 239 55 192 127 0 0 96 108 17 232 252 127 0 0 2 0 0 0 0 0 0 0 0 110 17 232 252 127 0 0
Nonce to get the hash was 1
It took 0.000000 seconds to calculate
Hash was 0 0 0 0 0 0 0 0 6 107 181 157 222 127 0 0 64 183 143 12 253 127 0 0 129 123 181 157 222 127 0 0 0 139 201 157 222 127 0 0 16 183 143 12 253 127 0 0 2 0 0 0 0 0 0 0 176 184 143 12 253 127 0 0
Nonce to get the hash was 1
It took 0.000000 seconds to calculate
Hash was 0 0 0 0 0 0 0 0 6 139 121 81 110 127 0 0 32 171 61 179 254 127 0 0 129 155 121 81 110 127 0 0 0 171 141 81 110 127 0 0 240 170 61 179 254 127 0 0 2 0 0 0 0 0 0 0 144 172 61 179 254 127 0 0
Nonce to get the hash was 1
It took 0.000000 seconds to calculate