Skip to content

Instantly share code, notes, and snippets.

@philronan
Created June 12, 2018 11:10
Show Gist options
  • Save philronan/49458736a2f08ecdff7b60eb6fc6f565 to your computer and use it in GitHub Desktop.
Save philronan/49458736a2f08ecdff7b60eb6fc6f565 to your computer and use it in GitHub Desktop.
A proof of work function based on SHA256 hashes; finds a string with a given prefix whose hash value ends in the required number of zero bits
/* compile with: cc -Wall -O3 sha256_proof_of_work.c -o sha256_proof_of_work -lcrypto */
#include <openssl/sha.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define PREFIX_BYTES 16
#define MAX_HASH_ATTEMPTS 10000000000L
uint8_t *sha256_proof_of_work(const uint8_t prefix[PREFIX_BYTES], int strength);
int main(int argc, char **argv) {
uint8_t p[PREFIX_BYTES];
uint8_t *result;
FILE *f;
int i, nbits = 10;
if (argc == 2) nbits = atoi(argv[1]);
if (nbits < 1) nbits = 1;
if (nbits > 24) nbits = 24;
printf("Searching for a hash with %d trailing zero bits\n", nbits);
f = fopen("/dev/urandom", "r");
fread(p, PREFIX_BYTES, 1, f);
fclose(f);
printf("Prefix: ");
for (i=0; i<PREFIX_BYTES; i++) {
printf("%02x", p[i]);
}
putchar('\n');
result = sha256_proof_of_work(p, nbits);
if (!result) {
puts("No hash found");
return 1;
}
printf("Output: ");
for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
printf("%02x", *result++);
putchar('\n');
return 0;
}
uint8_t *sha256_proof_of_work(const uint8_t prefix[PREFIX_BYTES], int strength) {
static uint8_t hash_in[SHA256_DIGEST_LENGTH];
uint8_t hash_out[SHA256_DIGEST_LENGTH];
int i, j, iszero;
long nhashes;
int zbytes = strength >> 3;
int zbits = ~(~0 << (strength & 0x07));
for (i=0; i<PREFIX_BYTES; i++) hash_in[i] = prefix[i];
for ( ; i<SHA256_DIGEST_LENGTH; i++) hash_in[i] = 0;
for (nhashes=0; nhashes<MAX_HASH_ATTEMPTS; nhashes++) {
SHA256(hash_in, SHA256_DIGEST_LENGTH, hash_out);
iszero = 1;
for (i=SHA256_DIGEST_LENGTH-1; i>=SHA256_DIGEST_LENGTH-zbytes; i--) {
if (hash_out[i]) {
iszero = 0;
break;
}
}
if (iszero && (hash_out[i] & zbits) == 0) {
return hash_in;
}
j = SHA256_DIGEST_LENGTH-1;
while (!(++hash_in[j])) j--;
}
return NULL; /* No hash found after MAX_HASH_ATTEMPTS; request another prefix? */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment