bitmessage-js/src/pow.cc

127 lines
3.1 KiB
C++
Raw Normal View History

2015-01-09 21:36:42 +00:00
// Based on <https://github.com/grant-olson/bitmessage-powfaster>
// fastcpu implementation.
// TODO(Kagami): Port it to WIN32 (see bitmessage-powfaster for an
// example).
2015-01-09 22:36:28 +00:00
#define __STDC_LIMIT_MACROS
2015-01-09 21:36:42 +00:00
#include <stdint.h>
#include <string.h>
2015-01-10 16:29:33 +00:00
#include <pthread.h>
2015-01-09 21:36:42 +00:00
#include <arpa/inet.h>
#include <openssl/sha.h>
#define HASH_SIZE 64
2015-01-10 16:29:33 +00:00
#define NTOHLL(x) \
( \
((uint64_t)(ntohl( (unsigned int)((x << 32) >> 32) )) << 32) | \
ntohl( ((unsigned int)(x >> 32)) ) \
)
#define SET_RESULT(res, nonce) \
{ \
pthread_mutex_lock(&g_mutex); \
if (g_result == RESULT_NOT_READY) { \
g_result = res; \
g_nonce = nonce; \
} \
pthread_mutex_unlock(&g_mutex); \
}
2015-01-09 21:36:42 +00:00
2015-01-10 16:29:33 +00:00
typedef enum {
RESULT_NOT_READY,
RESULT_OK,
RESULT_OVERFLOW,
RESULT_ERROR
} Result;
// Global arguments.
size_t g_pool_size;
uint64_t g_target;
uint8_t* g_initial_hash;
uint64_t g_max_nonce;
// Shared variables for threads.
pthread_mutex_t g_mutex;
Result g_result = RESULT_NOT_READY;
uint64_t g_nonce;
void* pow_thread(void* num) {
uint64_t i = *((size_t *)num);
2015-01-09 21:36:42 +00:00
uint8_t message[HASH_SIZE+sizeof(uint64_t)];
uint8_t digest[HASH_SIZE];
uint64_t* be_nonce;
uint64_t* be_trial;
SHA512_CTX sha;
2015-01-10 16:29:33 +00:00
memcpy(message+sizeof(uint64_t), g_initial_hash, HASH_SIZE);
2015-01-09 21:36:42 +00:00
be_nonce = (uint64_t *)message;
be_trial = (uint64_t *)digest;
2015-01-09 22:09:01 +00:00
2015-01-10 16:29:33 +00:00
while (g_result == RESULT_NOT_READY) {
2015-01-09 21:36:42 +00:00
// This is very unlikely to be ever happen but it's better to be
// sure anyway.
2015-01-10 16:29:33 +00:00
if (i > g_max_nonce) {
SET_RESULT(RESULT_OVERFLOW, 0);
return NULL;
2015-01-09 21:36:42 +00:00
}
*be_nonce = NTOHLL(i);
SHA512_Init(&sha);
SHA512_Update(&sha, message, HASH_SIZE+sizeof(uint64_t));
SHA512_Final(digest, &sha);
SHA512_Init(&sha);
SHA512_Update(&sha, digest, HASH_SIZE);
SHA512_Final(digest, &sha);
2015-01-10 16:29:33 +00:00
if (NTOHLL(*be_trial) <= g_target) {
SET_RESULT(RESULT_OK, i);
return NULL;
}
i += g_pool_size;
}
return NULL;
}
int pow(size_t pool_size,
uint64_t target,
const uint8_t* initial_hash,
uint64_t max_nonce,
uint64_t* nonce) {
g_pool_size = pool_size;
g_target = target;
g_initial_hash = (uint8_t *)initial_hash;
g_max_nonce = max_nonce ? max_nonce : UINT64_MAX;
pthread_mutex_init(&g_mutex, NULL);
pthread_t threads[pool_size];
size_t args[pool_size];
size_t i;
int error;
for (i = 0; i < pool_size; i++) {
args[i] = i;
error = pthread_create(&threads[i], NULL, pow_thread, &args[i]);
if (error) {
SET_RESULT(RESULT_ERROR, 0);
2015-01-09 21:36:42 +00:00
break;
}
}
2015-01-09 22:09:01 +00:00
2015-01-10 16:29:33 +00:00
// Wait for only spawned threads.
while (i--) {
pthread_join(threads[i], NULL);
}
switch (g_result) {
case RESULT_OK:
*nonce = g_nonce;
error = 0;
break;
case RESULT_OVERFLOW:
error = -1;
break;
default:
error = -2;
}
pthread_mutex_destroy(&g_mutex);
return error;
2015-01-09 21:36:42 +00:00
}