Browse Source

Coding style "adjustment"

- Adjusting the coding style for consistency after the talk we had
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
7fd1dd36f5
  1. 1476
      data_sizes.h
  2. 102
      ethash.h
  3. 578
      internal.c
  4. 26
      internal.h
  5. 88
      io.c
  6. 54
      io.h
  7. 74
      io_posix.c
  8. 76
      io_win32.c
  9. 194
      sha3.c
  10. 6
      sha3.h
  11. 10
      sha3_cryptopp.cpp
  12. 2
      util.c

1476
data_sizes.h

File diff suppressed because it is too large

102
ethash.h

@ -44,27 +44,27 @@ extern "C" {
// LTODO: for consistency's sake maybe use ethash_params_t? // LTODO: for consistency's sake maybe use ethash_params_t?
typedef struct ethash_params { typedef struct ethash_params {
/// Size of full data set (in bytes, multiple of mix size (128)). /// Size of full data set (in bytes, multiple of mix size (128)).
uint64_t full_size; uint64_t full_size;
/// Size of compute cache (in bytes, multiple of node size (64)). /// Size of compute cache (in bytes, multiple of node size (64)).
uint64_t cache_size; uint64_t cache_size;
} ethash_params; } ethash_params;
/// Type of a seedhash/blockhash e.t.c. /// Type of a seedhash/blockhash e.t.c.
typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t; typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t;
static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i) static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i)
{ {
return hash->b[i]; return hash->b[i];
} }
static inline void ethash_h256_set(ethash_h256_t *hash, unsigned int i, uint8_t v) static inline void ethash_h256_set(ethash_h256_t *hash, unsigned int i, uint8_t v)
{ {
hash->b[i] = v; hash->b[i] = v;
} }
static inline void ethash_h256_reset(ethash_h256_t *hash) static inline void ethash_h256_reset(ethash_h256_t *hash)
{ {
memset(hash, 0, 32); memset(hash, 0, 32);
} }
struct ethash_light; struct ethash_light;
@ -75,8 +75,8 @@ typedef int(*ethash_callback_t)(unsigned);
// LTODO: for consistency's sake maybe use ethash_return_value_t? // LTODO: for consistency's sake maybe use ethash_return_value_t?
typedef struct ethash_return_value { typedef struct ethash_return_value {
ethash_h256_t result; ethash_h256_t result;
ethash_h256_t mix_hash; ethash_h256_t mix_hash;
} ethash_return_value; } ethash_return_value;
uint64_t ethash_get_datasize(const uint32_t block_number); uint64_t ethash_get_datasize(const uint32_t block_number);
@ -84,13 +84,13 @@ uint64_t ethash_get_cachesize(const uint32_t block_number);
// initialize the parameters // initialize the parameters
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) { static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
params->full_size = ethash_get_datasize(block_number); params->full_size = ethash_get_datasize(block_number);
params->cache_size = ethash_get_cachesize(block_number); params->cache_size = ethash_get_cachesize(block_number);
} }
// LTODO: for consistency's sake maybe use ethash_cache_t? // LTODO: for consistency's sake maybe use ethash_cache_t?
typedef struct ethash_cache { typedef struct ethash_cache {
void *mem; void *mem;
} ethash_cache; } ethash_cache;
/** /**
@ -106,7 +106,7 @@ typedef struct ethash_cache {
ethash_cache *ethash_cache_new(ethash_params const *params, ethash_h256_t const *seed); ethash_cache *ethash_cache_new(ethash_params const *params, ethash_h256_t const *seed);
/** /**
* Frees a previously allocated ethash_cache * Frees a previously allocated ethash_cache
* @param c The object to free * @param c The object to free
*/ */
void ethash_cache_delete(ethash_cache *c); void ethash_cache_delete(ethash_cache *c);
@ -123,7 +123,7 @@ void ethash_cache_delete(ethash_cache *c);
ethash_light_t ethash_light_new(ethash_params const *params, ethash_h256_t const *seed); ethash_light_t ethash_light_new(ethash_params const *params, ethash_h256_t const *seed);
/** /**
* Frees a previously allocated ethash_light handler * Frees a previously allocated ethash_light handler
* @param light The light handler to free * @param light The light handler to free
*/ */
void ethash_light_delete(ethash_light_t light); void ethash_light_delete(ethash_light_t light);
/** /**
@ -138,10 +138,10 @@ void ethash_light_delete(ethash_light_t light);
* parameters given. * parameters given.
*/ */
bool ethash_light_compute(ethash_return_value *ret, bool ethash_light_compute(ethash_return_value *ret,
ethash_light_t light, ethash_light_t light,
ethash_params const *params, ethash_params const *params,
const ethash_h256_t *header_hash, const ethash_h256_t *header_hash,
const uint64_t nonce); const uint64_t nonce);
/** /**
* Get a pointer to the cache object held by the light client * Get a pointer to the cache object held by the light client
* *
@ -176,8 +176,8 @@ ethash_cache *ethash_light_acquire_cache(ethash_light_t light);
* ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
*/ */
ethash_full_t ethash_full_new(ethash_params const* params, ethash_full_t ethash_full_new(ethash_params const* params,
ethash_cache const* cache, ethash_cache const* cache,
ethash_callback_t callback); ethash_callback_t callback);
/** /**
* Frees a previously allocated ethash_full handler * Frees a previously allocated ethash_full handler
* @param full The light handler to free * @param full The light handler to free
@ -190,16 +190,16 @@ void ethash_full_delete(ethash_full_t full);
* @param full The full client handler * @param full The full client handler
* @param params The parameters to use * @param params The parameters to use
* @param header_hash The header hash to pack into the mix * @param header_hash The header hash to pack into the mix
* @param nonce The nonce to pack into the mix * @param nonce The nonce to pack into the mix
* @return true if all went well and false if there were invalid * @return true if all went well and false if there were invalid
* parameters given or if there was a callback given and * parameters given or if there was a callback given and
* at some point return a non-zero value * at some point return a non-zero value
*/ */
bool ethash_full_compute(ethash_return_value *ret, bool ethash_full_compute(ethash_return_value *ret,
ethash_full_t full, ethash_full_t full,
ethash_params const *params, ethash_params const *params,
const ethash_h256_t *header_hash, const ethash_h256_t *header_hash,
const uint64_t nonce); const uint64_t nonce);
/** /**
* Get a pointer to the cache object held by the full client * Get a pointer to the cache object held by the full client
* *
@ -221,27 +221,27 @@ void ethash_get_seedhash(ethash_h256_t *seedhash, const uint32_t block_number);
// Returns if hash is less than or equal to difficulty // Returns if hash is less than or equal to difficulty
static inline int ethash_check_difficulty(ethash_h256_t const *hash, static inline int ethash_check_difficulty(ethash_h256_t const *hash,
ethash_h256_t const *difficulty) ethash_h256_t const *difficulty)
{ {
// Difficulty is big endian // Difficulty is big endian
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) { if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
continue; continue;
} }
return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i); return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
} }
return 1; return 1;
} }
int ethash_quick_check_difficulty(ethash_h256_t const *header_hash, int ethash_quick_check_difficulty(ethash_h256_t const *header_hash,
const uint64_t nonce, const uint64_t nonce,
ethash_h256_t const *mix_hash, ethash_h256_t const *mix_hash,
ethash_h256_t const *difficulty); ethash_h256_t const *difficulty);
/** /**
* ========================= * =========================
* = DEPRECATED API = * = DEPRECATED API =
* ========================= * =========================
* *
* Kept for backwards compatibility with whoever still uses it. Please consider * Kept for backwards compatibility with whoever still uses it. Please consider
@ -249,22 +249,22 @@ int ethash_quick_check_difficulty(ethash_h256_t const *header_hash,
*/ */
void ethash_mkcache(ethash_cache *cache, ethash_params const *params, ethash_h256_t const *seed); void ethash_mkcache(ethash_cache *cache, ethash_params const *params, ethash_h256_t const *seed);
void ethash_full(ethash_return_value *ret, void ethash_full(ethash_return_value *ret,
void const *full_mem, void const *full_mem,
ethash_params const *params, ethash_params const *params,
ethash_h256_t const *header_hash, ethash_h256_t const *header_hash,
const uint64_t nonce); const uint64_t nonce);
void ethash_light(ethash_return_value *ret, void ethash_light(ethash_return_value *ret,
ethash_cache const *cache, ethash_cache const *cache,
ethash_params const *params, ethash_params const *params,
ethash_h256_t const *header_hash, ethash_h256_t const *header_hash,
const uint64_t nonce); const uint64_t nonce);
/** /**
* Compute the memory data for a full node's memory * Compute the memory data for a full node's memory
* *
* @param mem A pointer to an ethash full's memory * @param mem A pointer to an ethash full's memory
* @param params The parameters to compute the data with * @param params The parameters to compute the data with
* @param cache A cache object to use in the calculation * @param cache A cache object to use in the calculation
* @return true if all went fine and false for invalid parameters * @return true if all went fine and false for invalid parameters
*/ */
bool ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); bool ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);

578
internal.c

@ -8,11 +8,11 @@
ethash is distributed in the hope that it will be useful, ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file internal.c /** @file internal.c
* @author Tim Hughes <tim@twistedfury.com> * @author Tim Hughes <tim@twistedfury.com>
@ -38,411 +38,413 @@
#endif // WITH_CRYPTOPP #endif // WITH_CRYPTOPP
uint64_t ethash_get_datasize(const uint32_t block_number) { uint64_t ethash_get_datasize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 2048); assert(block_number / EPOCH_LENGTH < 2048);
return dag_sizes[block_number / EPOCH_LENGTH]; return dag_sizes[block_number / EPOCH_LENGTH];
} }
uint64_t ethash_get_cachesize(const uint32_t block_number) { uint64_t ethash_get_cachesize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 2048); assert(block_number / EPOCH_LENGTH < 2048);
return cache_sizes[block_number / EPOCH_LENGTH]; return cache_sizes[block_number / EPOCH_LENGTH];
} }
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
// SeqMemoHash(s, R, N) // SeqMemoHash(s, R, N)
bool static ethash_compute_cache_nodes(node *const nodes, bool static ethash_compute_cache_nodes(node *const nodes,
ethash_params const *params, ethash_params const *params,
ethash_h256_t const* seed) ethash_h256_t const* seed)
{ {
if (params->cache_size % sizeof(node) != 0) { if (params->cache_size % sizeof(node) != 0) {
return false; return false;
} }
uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node)); uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node));
SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32); SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32);
for (unsigned i = 1; i != num_nodes; ++i) { for (unsigned i = 1; i != num_nodes; ++i) {
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64); SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
} }
for (unsigned j = 0; j != CACHE_ROUNDS; j++) { for (unsigned j = 0; j != CACHE_ROUNDS; j++) {
for (unsigned i = 0; i != num_nodes; i++) { for (unsigned i = 0; i != num_nodes; i++) {
uint32_t const idx = nodes[i].words[0] % num_nodes; uint32_t const idx = nodes[i].words[0] % num_nodes;
node data; node data;
data = nodes[(num_nodes - 1 + i) % num_nodes]; data = nodes[(num_nodes - 1 + i) % num_nodes];
for (unsigned w = 0; w != NODE_WORDS; ++w) { for (unsigned w = 0; w != NODE_WORDS; ++w) {
data.words[w] ^= nodes[idx].words[w]; data.words[w] ^= nodes[idx].words[w];
} }
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
} }
} }
fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS);
return true; // now perform endian conversion
fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS);
return true;
} }
ethash_cache *ethash_cache_new(ethash_params const *params, ethash_h256_t const *seed) ethash_cache *ethash_cache_new(ethash_params const *params, ethash_h256_t const *seed)
{ {
ethash_cache *ret; ethash_cache *ret;
ret = malloc(sizeof(*ret)); ret = malloc(sizeof(*ret));
if (!ret) { if (!ret) {
return NULL; return NULL;
} }
ret->mem = malloc((size_t)params->cache_size); ret->mem = malloc((size_t)params->cache_size);
if (!ret->mem) { if (!ret->mem) {
goto fail_free_cache; goto fail_free_cache;
} }
node *nodes = (node*)ret->mem; node *nodes = (node*)ret->mem;
if (!ethash_compute_cache_nodes(nodes, params, seed)) { if (!ethash_compute_cache_nodes(nodes, params, seed)) {
goto fail_free_cache_mem; goto fail_free_cache_mem;
} }
return ret; return ret;
fail_free_cache_mem: fail_free_cache_mem:
free(ret->mem); free(ret->mem);
fail_free_cache: fail_free_cache:
free(ret); free(ret);
return NULL; return NULL;
} }
void ethash_cache_delete(ethash_cache *c) void ethash_cache_delete(ethash_cache *c)
{ {
free(c->mem); free(c->mem);
free(c); free(c);
} }
void ethash_calculate_dag_item(node *const ret, void ethash_calculate_dag_item(node *const ret,
const unsigned node_index, const unsigned node_index,
const struct ethash_params *params, const struct ethash_params *params,
const struct ethash_cache *cache) const struct ethash_cache *cache)
{ {
uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache->mem; node const *cache_nodes = (node const *) cache->mem;
node const *init = &cache_nodes[node_index % num_parent_nodes]; node const *init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node)); memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index; ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node)); SHA3_512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = ret->xmm[0]; __m128i xmm0 = ret->xmm[0];
__m128i xmm1 = ret->xmm[1]; __m128i xmm1 = ret->xmm[1];
__m128i xmm2 = ret->xmm[2]; __m128i xmm2 = ret->xmm[2];
__m128i xmm3 = ret->xmm[3]; __m128i xmm3 = ret->xmm[3];
#endif #endif
for (unsigned i = 0; i != DATASET_PARENTS; ++i) { for (unsigned i = 0; i != DATASET_PARENTS; ++i) {
uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes; uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index]; node const *parent = &cache_nodes[parent_index];
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
{ {
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
// have to write to ret as values are used to compute index // have to write to ret as values are used to compute index
ret->xmm[0] = xmm0; ret->xmm[0] = xmm0;
ret->xmm[1] = xmm1; ret->xmm[1] = xmm1;
ret->xmm[2] = xmm2; ret->xmm[2] = xmm2;
ret->xmm[3] = xmm3; ret->xmm[3] = xmm3;
} }
#else #else
{ {
for (unsigned w = 0; w != NODE_WORDS; ++w) { for (unsigned w = 0; w != NODE_WORDS; ++w) {
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
} }
} }
#endif #endif
} }
SHA3_512(ret->bytes, ret->bytes, sizeof(node)); SHA3_512(ret->bytes, ret->bytes, sizeof(node));
} }
bool ethash_compute_full_data(void *mem, bool ethash_compute_full_data(void *mem,
ethash_params const *params, ethash_params const *params,
ethash_cache const *cache) ethash_cache const *cache)
{ {
if (params->full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 || if (params->full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 ||
(params->full_size % sizeof(node)) != 0) { (params->full_size % sizeof(node)) != 0) {
return false; return false;
} }
node *full_nodes = mem; node *full_nodes = mem;
// now compute full nodes // now compute full nodes
for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) { for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) {
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache); ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache);
} }
return true; return true;
} }
static bool ethash_hash(ethash_return_value *ret, static bool ethash_hash(ethash_return_value *ret,
node const *full_nodes, node const *full_nodes,
ethash_cache const *cache, ethash_cache const *cache,
ethash_params const *params, ethash_params const *params,
ethash_h256_t const *header_hash, ethash_h256_t const *header_hash,
const uint64_t nonce, const uint64_t nonce,
ethash_callback_t callback) ethash_callback_t callback)
{ {
if (params->full_size % MIX_WORDS != 0) { if (params->full_size % MIX_WORDS != 0) {
return false; return false;
} }
// pack hash and nonce together into first 40 bytes of s_mix // pack hash and nonce together into first 40 bytes of s_mix
assert(sizeof(node) * 8 == 512); assert(sizeof(node) * 8 == 512);
node s_mix[MIX_NODES + 1]; node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, header_hash, 32); memcpy(s_mix[0].bytes, header_hash, 32);
fix_endian64(s_mix[0].double_words[4], nonce); fix_endian64(s_mix[0].double_words[4], nonce);
// compute sha3-512 hash and replicate across mix // compute sha3-512 hash and replicate across mix
SHA3_512(s_mix->bytes, s_mix->bytes, 40); SHA3_512(s_mix->bytes, s_mix->bytes, 40);
fix_endian_arr32(s_mix[0].words, 16); fix_endian_arr32(s_mix[0].words, 16);
node *const mix = s_mix + 1; node *const mix = s_mix + 1;
for (unsigned w = 0; w != MIX_WORDS; ++w) { for (unsigned w = 0; w != MIX_WORDS; ++w) {
mix->words[w] = s_mix[0].words[w % NODE_WORDS]; mix->words[w] = s_mix[0].words[w % NODE_WORDS];
} }
unsigned const unsigned const
page_size = sizeof(uint32_t) * MIX_WORDS, page_size = sizeof(uint32_t) * MIX_WORDS,
num_full_pages = (unsigned) (params->full_size / page_size); num_full_pages = (unsigned) (params->full_size / page_size);
for (unsigned i = 0; i != ACCESSES; ++i) { for (unsigned i = 0; i != ACCESSES; ++i) {
uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages; uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned n = 0; n != MIX_NODES; ++n) { for (unsigned n = 0; n != MIX_NODES; ++n) {
const node *dag_node; const node *dag_node;
if (callback && if (callback &&
callback(((float)(i * n) / (float)(ACCESSES * MIX_NODES) * 100) != 0)) { callback(((float)(i * n) / (float)(ACCESSES * MIX_NODES) * 100) != 0)) {
return false; return false;
} }
if (full_nodes) { if (full_nodes) {
dag_node = &full_nodes[MIX_NODES * index + n]; dag_node = &full_nodes[MIX_NODES * index + n];
} else { } else {
node tmp_node; node tmp_node;
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, params, cache); ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, params, cache);
dag_node = &tmp_node; dag_node = &tmp_node;
} }
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
{ {
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
__m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]); __m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]);
__m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]); __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]);
__m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]); __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]);
mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]); mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]); mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]);
mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]); mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]); mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
} }
#else #else
{ {
for (unsigned w = 0; w != NODE_WORDS; ++w) { for (unsigned w = 0; w != NODE_WORDS; ++w) {
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]); mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
} }
} }
#endif #endif
} }
} }
// compress mix // compress mix
for (unsigned w = 0; w != MIX_WORDS; w += 4) { for (unsigned w = 0; w != MIX_WORDS; w += 4) {
uint32_t reduction = mix->words[w + 0]; uint32_t reduction = mix->words[w + 0];
reduction = reduction * FNV_PRIME ^ mix->words[w + 1]; reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
reduction = reduction * FNV_PRIME ^ mix->words[w + 2]; reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
reduction = reduction * FNV_PRIME ^ mix->words[w + 3]; reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
mix->words[w / 4] = reduction; mix->words[w / 4] = reduction;
} }
fix_endian_arr32(mix->words, MIX_WORDS / 4); fix_endian_arr32(mix->words, MIX_WORDS / 4);
memcpy(&ret->mix_hash, mix->bytes, 32); memcpy(&ret->mix_hash, mix->bytes, 32);
// final Keccak hash // final Keccak hash
SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
return true; return true;
} }
void ethash_quick_hash(ethash_h256_t *return_hash, void ethash_quick_hash(ethash_h256_t *return_hash,
ethash_h256_t const *header_hash, ethash_h256_t const *header_hash,
const uint64_t nonce, const uint64_t nonce,
ethash_h256_t const *mix_hash) ethash_h256_t const *mix_hash)
{ {
uint8_t buf[64 + 32]; uint8_t buf[64 + 32];
memcpy(buf, header_hash, 32); memcpy(buf, header_hash, 32);
fix_endian64_same(nonce); fix_endian64_same(nonce);
memcpy(&(buf[32]), &nonce, 8); memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40); SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32); memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64 + 32); SHA3_256(return_hash, buf, 64 + 32);
} }
void ethash_get_seedhash(ethash_h256_t *seedhash, const uint32_t block_number) void ethash_get_seedhash(ethash_h256_t *seedhash, const uint32_t block_number)
{ {
ethash_h256_reset(seedhash); ethash_h256_reset(seedhash);
const uint32_t epochs = block_number / EPOCH_LENGTH; const uint32_t epochs = block_number / EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i) for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(seedhash, (uint8_t*)seedhash, 32); SHA3_256(seedhash, (uint8_t*)seedhash, 32);
} }
int ethash_quick_check_difficulty(ethash_h256_t const *header_hash, int ethash_quick_check_difficulty(ethash_h256_t const *header_hash,
const uint64_t nonce, const uint64_t nonce,
ethash_h256_t const *mix_hash, ethash_h256_t const *mix_hash,
ethash_h256_t const *difficulty) ethash_h256_t const *difficulty)
{ {
ethash_h256_t return_hash; ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash); ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
return ethash_check_difficulty(&return_hash, difficulty); return ethash_check_difficulty(&return_hash, difficulty);
} }
ethash_light_t ethash_light_new(ethash_params const *params, ethash_h256_t const *seed) ethash_light_t ethash_light_new(ethash_params const *params, ethash_h256_t const *seed)
{ {
struct ethash_light *ret; struct ethash_light *ret;
ret = calloc(sizeof(*ret), 1); ret = calloc(sizeof(*ret), 1);
if (!ret) { if (!ret) {
return NULL; return NULL;
} }
ret->cache = ethash_cache_new(params, seed); ret->cache = ethash_cache_new(params, seed);
if (!ret->cache) { if (!ret->cache) {
goto fail_free_light; goto fail_free_light;
} }
return ret; return ret;
fail_free_light: fail_free_light:
free(ret); free(ret);
return NULL; return NULL;
} }
void ethash_light_delete(ethash_light_t light) void ethash_light_delete(ethash_light_t light)
{ {
if (light->cache) { if (light->cache) {
ethash_cache_delete(light->cache); ethash_cache_delete(light->cache);
} }
free(light); free(light);
} }
bool ethash_light_compute(ethash_return_value *ret, bool ethash_light_compute(ethash_return_value *ret,
ethash_light_t light, ethash_light_t light,
ethash_params const *params, ethash_params const *params,
const ethash_h256_t *header_hash, const ethash_h256_t *header_hash,
const uint64_t nonce) const uint64_t nonce)
{ {
return ethash_hash(ret, NULL, light->cache, params, header_hash, nonce, NULL); return ethash_hash(ret, NULL, light->cache, params, header_hash, nonce, NULL);
} }
ethash_cache *ethash_light_get_cache(ethash_light_t light) ethash_cache *ethash_light_get_cache(ethash_light_t light)
{ {
return light->cache; return light->cache;
} }
ethash_cache *ethash_light_acquire_cache(ethash_light_t light) ethash_cache *ethash_light_acquire_cache(ethash_light_t light)
{ {
ethash_cache* ret = light->cache; ethash_cache* ret = light->cache;
light->cache = 0; light->cache = 0;
return ret; return ret;
} }
ethash_full_t ethash_full_new(ethash_params const* params, ethash_full_t ethash_full_new(ethash_params const* params,
ethash_cache const* cache, ethash_cache const* cache,
ethash_callback_t callback) ethash_callback_t callback)
{ {
struct ethash_full *ret; struct ethash_full *ret;
ret = calloc(sizeof(*ret), 1); ret = calloc(sizeof(*ret), 1);
if (!ret) { if (!ret) {
return NULL; return NULL;
} }
ret->cache = (ethash_cache*)cache; ret->cache = (ethash_cache*)cache;
ret->data = malloc((size_t)params->full_size); ret->data = malloc((size_t)params->full_size);
if (!ret->data) { if (!ret->data) {
goto fail_free_full; goto fail_free_full;
} }
if (!ethash_compute_full_data(ret->data, params, cache)) { if (!ethash_compute_full_data(ret->data, params, cache)) {
goto fail_free_full_data; goto fail_free_full_data;
} }
ret->callback = callback; ret->callback = callback;
return ret; return ret;
fail_free_full_data: fail_free_full_data:
free(ret->data); free(ret->data);
fail_free_full: fail_free_full:
free(ret); free(ret);
return NULL; return NULL;
} }
void ethash_full_delete(ethash_full_t full) void ethash_full_delete(ethash_full_t full)
{ {
if (full->cache) { if (full->cache) {
ethash_cache_delete(full->cache); ethash_cache_delete(full->cache);
} }
free(full->data); free(full->data);
free(full); free(full);
} }
bool ethash_full_compute(ethash_return_value *ret, bool ethash_full_compute(ethash_return_value *ret,
ethash_full_t full, ethash_full_t full,
ethash_params const *params, ethash_params const *params,
const ethash_h256_t *header_hash, const ethash_h256_t *header_hash,
const uint64_t nonce) const uint64_t nonce)
{ {
return ethash_hash(ret, return ethash_hash(ret,
(node const*)full->data, (node const*)full->data,
NULL, NULL,
params, params,
header_hash, header_hash,
nonce, nonce,
full->callback); full->callback);
} }
ethash_cache *ethash_full_get_cache(ethash_full_t full) ethash_cache *ethash_full_get_cache(ethash_full_t full)
{ {
return full->cache; return full->cache;
} }
ethash_cache *ethash_full_acquire_cache(ethash_full_t full) ethash_cache *ethash_full_acquire_cache(ethash_full_t full)
{ {
ethash_cache* ret = full->cache; ethash_cache* ret = full->cache;
full->cache = 0; full->cache = 0;
return ret; return ret;
} }
/** /**
* ========================= * =========================
* = DEPRECATED API = * = DEPRECATED API =
* ========================= * =========================
* *
* Kept for backwards compatibility with whoever still uses it. Please consider * Kept for backwards compatibility with whoever still uses it. Please consider
* switching to the new API (look above) * switching to the new API (look above)
*/ */
void ethash_mkcache(ethash_cache *cache, void ethash_mkcache(ethash_cache *cache,
ethash_params const *params, ethash_params const *params,
ethash_h256_t const* seed) ethash_h256_t const* seed)
{ {
node *nodes = (node*) cache->mem; node *nodes = (node*) cache->mem;
ethash_compute_cache_nodes(nodes, params, seed); ethash_compute_cache_nodes(nodes, params, seed);
} }
void ethash_full(ethash_return_value *ret, void ethash_full(ethash_return_value *ret,
void const *full_mem, void const *full_mem,
ethash_params const *params, ethash_params const *params,
ethash_h256_t const *header_hash, ethash_h256_t const *header_hash,
const uint64_t nonce) const uint64_t nonce)
{ {
ethash_hash(ret, (node const *) full_mem, NULL, params, header_hash, nonce, NULL); ethash_hash(ret, (node const *) full_mem, NULL, params, header_hash, nonce, NULL);
} }
void ethash_light(ethash_return_value *ret, void ethash_light(ethash_return_value *ret,
ethash_cache const *cache, ethash_cache const *cache,
ethash_params const *params, ethash_params const *params,
ethash_h256_t const *header_hash, ethash_h256_t const *header_hash,
const uint64_t nonce) const uint64_t nonce)
{ {
ethash_hash(ret, NULL, cache, params, header_hash, nonce, NULL); ethash_hash(ret, NULL, cache, params, header_hash, nonce, NULL);
} }

26
internal.h

@ -20,9 +20,9 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
typedef union node { typedef union node {
uint8_t bytes[NODE_WORDS * 4]; uint8_t bytes[NODE_WORDS * 4];
uint32_t words[NODE_WORDS]; uint32_t words[NODE_WORDS];
uint64_t double_words[NODE_WORDS / 2]; uint64_t double_words[NODE_WORDS / 2];
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
__m128i xmm[NODE_WORDS/4]; __m128i xmm[NODE_WORDS/4];
@ -31,24 +31,24 @@ typedef union node {
} node; } node;
struct ethash_light { struct ethash_light {
ethash_cache *cache; ethash_cache *cache;
}; };
struct ethash_full { struct ethash_full {
ethash_cache *cache; ethash_cache *cache;
node *data; node *data;
ethash_callback_t callback; ethash_callback_t callback;
}; };
void ethash_calculate_dag_item(node *const ret, void ethash_calculate_dag_item(node *const ret,
const unsigned node_index, const unsigned node_index,
ethash_params const *params, ethash_params const *params,
ethash_cache const *cache); ethash_cache const *cache);
void ethash_quick_hash(ethash_h256_t *return_hash, void ethash_quick_hash(ethash_h256_t *return_hash,
ethash_h256_t const *header_hash, ethash_h256_t const *header_hash,
const uint64_t nonce, const uint64_t nonce,
ethash_h256_t const *mix_hash); ethash_h256_t const *mix_hash);
#ifdef __cplusplus #ifdef __cplusplus
} }

88
io.c

@ -26,64 +26,64 @@
#define PASS_ARR(c_) (c_), sizeof(c_) #define PASS_ARR(c_) (c_), sizeof(c_)
static bool ethash_io_write_file(char const *dirname, static bool ethash_io_write_file(char const *dirname,
char const* filename, char const* filename,
size_t filename_length, size_t filename_length,
void const* data, void const* data,
size_t data_size) size_t data_size)
{ {
bool ret = false; bool ret = false;
char *fullname = ethash_io_create_filename(dirname, filename, filename_length); char *fullname = ethash_io_create_filename(dirname, filename, filename_length);
if (!fullname) { if (!fullname) {
return false; return false;
} }
FILE *f = ethash_fopen(fullname, "wb"); FILE *f = ethash_fopen(fullname, "wb");
if (!f) { if (!f) {
goto free_name; goto free_name;
} }
if (data_size != fwrite(data, 1, data_size, f)) { if (data_size != fwrite(data, 1, data_size, f)) {
goto close; goto close;
} }
ret = true; ret = true;
close: close:
fclose(f); fclose(f);
free_name: free_name:
free(fullname); free(fullname);
return ret; return ret;
} }
bool ethash_io_write(char const *dirname, bool ethash_io_write(char const *dirname,
ethash_params const* params, ethash_params const* params,
ethash_h256_t seedhash, ethash_h256_t seedhash,
void const* cache, void const* cache,
uint8_t **data, uint8_t **data,
uint64_t *data_size) uint64_t *data_size)
{ {
char info_buffer[DAG_MEMO_BYTESIZE]; char info_buffer[DAG_MEMO_BYTESIZE];
// allocate the bytes // allocate the bytes
uint8_t *temp_data_ptr = malloc((size_t)params->full_size); uint8_t *temp_data_ptr = malloc((size_t)params->full_size);
if (!temp_data_ptr) { if (!temp_data_ptr) {
goto end; goto end;
} }
ethash_compute_full_data(temp_data_ptr, params, cache); ethash_compute_full_data(temp_data_ptr, params, cache);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) { if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) {
goto fail_free; goto fail_free;
} }
ethash_io_serialize_info(REVISION, seedhash, info_buffer); ethash_io_serialize_info(REVISION, seedhash, info_buffer);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) { if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) {
goto fail_free; goto fail_free;
} }
*data = temp_data_ptr; *data = temp_data_ptr;
*data_size = params->full_size; *data_size = params->full_size;
return true; return true;
fail_free: fail_free:
free(temp_data_ptr); free(temp_data_ptr);
end: end:
return false; return false;
} }
#undef PASS_ARR #undef PASS_ARR

54
io.h

@ -36,9 +36,9 @@ static const char DAG_MEMO_NAME[] = "full.info";
/// Possible return values of @see ethash_io_prepare /// Possible return values of @see ethash_io_prepare
enum ethash_io_rc { enum ethash_io_rc {
ETHASH_IO_FAIL = 0, ///< There has been an IO failure ETHASH_IO_FAIL = 0, ///< There has been an IO failure
ETHASH_IO_MEMO_MISMATCH, ///< Memo file either did not exist or there was content mismatch ETHASH_IO_MEMO_MISMATCH, ///< Memo file either did not exist or there was content mismatch
ETHASH_IO_MEMO_MATCH, ///< Memo file existed and contents matched. No need to do anything ETHASH_IO_MEMO_MATCH, ///< Memo file existed and contents matched. No need to do anything
}; };
/** /**
@ -79,17 +79,17 @@ enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash)
* @return True for success and false in case of failure. * @return True for success and false in case of failure.
*/ */
bool ethash_io_write(char const *dirname, bool ethash_io_write(char const *dirname,
ethash_params const* params, ethash_params const* params,
ethash_h256_t seedhash, ethash_h256_t seedhash,
void const* cache, void const* cache,
uint8_t **data, uint8_t **data,
uint64_t *data_size); uint64_t *data_size);
/** /**
* An fopen wrapper for no-warnings crossplatform fopen. * An fopen wrapper for no-warnings crossplatform fopen.
* *
* Msvc compiler considers fopen to be insecure and suggests to use their * Msvc compiler considers fopen to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to * alternative. This is a wrapper for this alternative. Another way is to
* #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
* not sound like a good idea. * not sound like a good idea.
* *
@ -102,7 +102,7 @@ FILE *ethash_fopen(const char *file_name, const char *mode);
* An stncat wrapper for no-warnings crossplatform strncat. * An stncat wrapper for no-warnings crossplatform strncat.
* *
* Msvc compiler considers strncat to be insecure and suggests to use their * Msvc compiler considers strncat to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to * alternative. This is a wrapper for this alternative. Another way is to
* #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
* not sound like a good idea. * not sound like a good idea.
* *
@ -117,29 +117,29 @@ FILE *ethash_fopen(const char *file_name, const char *mode);
char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count); char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count);
static inline void ethash_io_serialize_info(uint32_t revision, static inline void ethash_io_serialize_info(uint32_t revision,
ethash_h256_t seed_hash, ethash_h256_t seed_hash,
char *output) char *output)
{ {
// if .info is only consumed locally we don't really care about endianess // if .info is only consumed locally we don't really care about endianess
memcpy(output, &revision, 4); memcpy(output, &revision, 4);
memcpy(output + 4, &seed_hash, 32); memcpy(output + 4, &seed_hash, 32);
} }
static inline char *ethash_io_create_filename(char const *dirname, static inline char *ethash_io_create_filename(char const *dirname,
char const* filename, char const* filename,
size_t filename_length) size_t filename_length)
{ {
size_t dirlen = strlen(dirname); size_t dirlen = strlen(dirname);
// in C the cast is not needed, but a C++ compiler will complain for invalid conversion // in C the cast is not needed, but a C++ compiler will complain for invalid conversion
char *name = (char*)malloc(dirlen + filename_length + 1); char *name = (char*)malloc(dirlen + filename_length + 1);
if (!name) { if (!name) {
return NULL; return NULL;
} }
name[0] = '\0'; name[0] = '\0';
ethash_strncat(name, dirlen + filename_length + 1, dirname, dirlen); ethash_strncat(name, dirlen + filename_length + 1, dirname, dirlen);
ethash_strncat(name, dirlen + filename_length + 1, filename, filename_length); ethash_strncat(name, dirlen + filename_length + 1, filename, filename_length);
return name; return name;
} }

74
io_posix.c

@ -29,58 +29,58 @@
FILE *ethash_fopen(const char *file_name, const char *mode) FILE *ethash_fopen(const char *file_name, const char *mode)
{ {
return fopen(file_name, mode); return fopen(file_name, mode);
} }
char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count) char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count)
{ {
return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL; return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL;
} }
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash) enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash)
{ {
char read_buffer[DAG_MEMO_BYTESIZE]; char read_buffer[DAG_MEMO_BYTESIZE];
char expect_buffer[DAG_MEMO_BYTESIZE]; char expect_buffer[DAG_MEMO_BYTESIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL; enum ethash_io_rc ret = ETHASH_IO_FAIL;
// assert directory exists, full owner permissions and read/search for others // assert directory exists, full owner permissions and read/search for others
int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (rc == -1 && errno != EEXIST) { if (rc == -1 && errno != EEXIST) {
goto end; goto end;
} }
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME)); char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME));
if (!memofile) { if (!memofile) {
goto end; goto end;
} }
// try to open memo file // try to open memo file
FILE *f = ethash_fopen(memofile, "rb"); FILE *f = ethash_fopen(memofile, "rb");
if (!f) { if (!f) {
// file does not exist, so no checking happens. All is fine. // file does not exist, so no checking happens. All is fine.
ret = ETHASH_IO_MEMO_MISMATCH; ret = ETHASH_IO_MEMO_MISMATCH;
goto free_memo; goto free_memo;
} }
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) { if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) {
goto close; goto close;
} }
ethash_io_serialize_info(REVISION, seedhash, expect_buffer); ethash_io_serialize_info(REVISION, seedhash, expect_buffer);
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
// we have different memo contents so delete the memo file // we have different memo contents so delete the memo file
if (unlink(memofile) != 0) { if (unlink(memofile) != 0) {
goto close; goto close;
} }
ret = ETHASH_IO_MEMO_MISMATCH; ret = ETHASH_IO_MEMO_MISMATCH;
} }
ret = ETHASH_IO_MEMO_MATCH; ret = ETHASH_IO_MEMO_MATCH;
close: close:
fclose(f); fclose(f);
free_memo: free_memo:
free(memofile); free(memofile);
end: end:
return ret; return ret;
} }

76
io_win32.c

@ -26,59 +26,59 @@
FILE *ethash_fopen(const char *file_name, const char *mode) FILE *ethash_fopen(const char *file_name, const char *mode)
{ {
FILE *f; FILE *f;
return fopen_s(&f, file_name, mode) == 0 ? f : NULL; return fopen_s(&f, file_name, mode) == 0 ? f : NULL;
} }
char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count) char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count)
{ {
return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL; return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL;
} }
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash) enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash)
{ {
char read_buffer[DAG_MEMO_BYTESIZE]; char read_buffer[DAG_MEMO_BYTESIZE];
char expect_buffer[DAG_MEMO_BYTESIZE]; char expect_buffer[DAG_MEMO_BYTESIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL; enum ethash_io_rc ret = ETHASH_IO_FAIL;
// assert directory exists // assert directory exists
int rc = _mkdir(dirname); int rc = _mkdir(dirname);
if (rc == -1 && errno != EEXIST) { if (rc == -1 && errno != EEXIST) {
goto end; goto end;
} }
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME)); char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME));
if (!memofile) { if (!memofile) {
goto end; goto end;
} }
// try to open memo file // try to open memo file
FILE *f = ethash_fopen(memofile, "rb"); FILE *f = ethash_fopen(memofile, "rb");
if (!f) { if (!f) {
// file does not exist, so no checking happens. All is fine. // file does not exist, so no checking happens. All is fine.
ret = ETHASH_IO_MEMO_MISMATCH; ret = ETHASH_IO_MEMO_MISMATCH;
goto free_memo; goto free_memo;
} }
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) { if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) {
goto close; goto close;
} }
ethash_io_serialize_info(REVISION, seedhash, expect_buffer); ethash_io_serialize_info(REVISION, seedhash, expect_buffer);
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
// we have different memo contents so delete the memo file // we have different memo contents so delete the memo file
if (_unlink(memofile) != 0) { if (_unlink(memofile) != 0) {
goto close; goto close;
} }
ret = ETHASH_IO_MEMO_MISMATCH; ret = ETHASH_IO_MEMO_MISMATCH;
} }
ret = ETHASH_IO_MEMO_MATCH; ret = ETHASH_IO_MEMO_MATCH;
close: close:
fclose(f); fclose(f);
free_memo: free_memo:
free(memofile); free(memofile);
end: end:
return ret; return ret;
} }

194
sha3.c

@ -17,65 +17,65 @@
/*** Constants. ***/ /*** Constants. ***/
static const uint8_t rho[24] = \ static const uint8_t rho[24] = \
{ 1, 3, 6, 10, 15, 21, { 1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44}; 62, 18, 39, 61, 20, 44};
static const uint8_t pi[24] = \ static const uint8_t pi[24] = \
{10, 7, 11, 17, 18, 3, {10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 15, 23, 19, 13, 12, 2,
20, 14, 22, 9, 6, 1}; 20, 14, 22, 9, 6, 1};
static const uint64_t RC[24] = \ static const uint64_t RC[24] = \
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
/*** Helper macros to unroll the permutation. ***/ /*** Helper macros to unroll the permutation. ***/
#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) #define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
#define REPEAT6(e) e e e e e e #define REPEAT6(e) e e e e e e
#define REPEAT24(e) REPEAT6(e e e e) #define REPEAT24(e) REPEAT6(e e e e)
#define REPEAT5(e) e e e e e #define REPEAT5(e) e e e e e
#define FOR5(v, s, e) \ #define FOR5(v, s, e) \
v = 0; \ v = 0; \
REPEAT5(e; v += s;) REPEAT5(e; v += s;)
/*** Keccak-f[1600] ***/ /*** Keccak-f[1600] ***/
static inline void keccakf(void* state) { static inline void keccakf(void* state) {
uint64_t* a = (uint64_t*)state; uint64_t* a = (uint64_t*)state;
uint64_t b[5] = {0}; uint64_t b[5] = {0};
uint64_t t = 0; uint64_t t = 0;
uint8_t x, y; uint8_t x, y;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
// Theta // Theta
FOR5(x, 1, FOR5(x, 1,
b[x] = 0; b[x] = 0;
FOR5(y, 5, FOR5(y, 5,
b[x] ^= a[x + y]; )) b[x] ^= a[x + y]; ))
FOR5(x, 1, FOR5(x, 1,
FOR5(y, 5, FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
// Rho and pi // Rho and pi
t = a[1]; t = a[1];
x = 0; x = 0;
REPEAT24(b[0] = a[pi[x]]; REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rol(t, rho[x]); a[pi[x]] = rol(t, rho[x]);
t = b[0]; t = b[0];
x++; ) x++; )
// Chi // Chi
FOR5(y, FOR5(y,
5, 5,
FOR5(x, 1, FOR5(x, 1,
b[x] = a[y + x];) b[x] = a[y + x];)
FOR5(x, 1, FOR5(x, 1,
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
// Iota // Iota
a[0] ^= RC[i]; a[0] ^= RC[i];
} }
} }
/******** The FIPS202-defined functions. ********/ /******** The FIPS202-defined functions. ********/
@ -83,20 +83,20 @@ static inline void keccakf(void* state) {
/*** Some helper macros. ***/ /*** Some helper macros. ***/
#define _(S) do { S } while (0) #define _(S) do { S } while (0)
#define FOR(i, ST, L, S) \ #define FOR(i, ST, L, S) \
_(for (size_t i = 0; i < L; i += ST) { S; }) _(for (size_t i = 0; i < L; i += ST) { S; })
#define mkapply_ds(NAME, S) \ #define mkapply_ds(NAME, S) \
static inline void NAME(uint8_t* dst, \ static inline void NAME(uint8_t* dst, \
const uint8_t* src, \ const uint8_t* src, \
size_t len) { \ size_t len) { \
FOR(i, 1, len, S); \ FOR(i, 1, len, S); \
} }
#define mkapply_sd(NAME, S) \ #define mkapply_sd(NAME, S) \
static inline void NAME(const uint8_t* src, \ static inline void NAME(const uint8_t* src, \
uint8_t* dst, \ uint8_t* dst, \
size_t len) { \ size_t len) { \
FOR(i, 1, len, S); \ FOR(i, 1, len, S); \
} }
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
mkapply_sd(setout, dst[i] = src[i]) // setout mkapply_sd(setout, dst[i] = src[i]) // setout
@ -105,47 +105,47 @@ mkapply_sd(setout, dst[i] = src[i]) // setout
#define Plen 200 #define Plen 200
// Fold P*F over the full blocks of an input. // Fold P*F over the full blocks of an input.
#define foldP(I, L, F) \ #define foldP(I, L, F) \
while (L >= rate) { \ while (L >= rate) { \
F(a, I, rate); \ F(a, I, rate); \
P(a); \ P(a); \
I += rate; \ I += rate; \
L -= rate; \ L -= rate; \
} }
/** The sponge-based hash construction. **/ /** The sponge-based hash construction. **/
static inline int hash(uint8_t* out, size_t outlen, static inline int hash(uint8_t* out, size_t outlen,
const uint8_t* in, size_t inlen, const uint8_t* in, size_t inlen,
size_t rate, uint8_t delim) { size_t rate, uint8_t delim) {
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
return -1; return -1;
} }
uint8_t a[Plen] = {0}; uint8_t a[Plen] = {0};
// Absorb input. // Absorb input.
foldP(in, inlen, xorin); foldP(in, inlen, xorin);
// Xor in the DS and pad frame. // Xor in the DS and pad frame.
a[inlen] ^= delim; a[inlen] ^= delim;
a[rate - 1] ^= 0x80; a[rate - 1] ^= 0x80;
// Xor in the last block. // Xor in the last block.
xorin(a, in, inlen); xorin(a, in, inlen);
// Apply P // Apply P
P(a); P(a);
// Squeeze output. // Squeeze output.
foldP(out, outlen, setout); foldP(out, outlen, setout);
setout(a, out, outlen); setout(a, out, outlen);
memset(a, 0, 200); memset(a, 0, 200);
return 0; return 0;
} }
#define defsha3(bits) \ #define defsha3(bits) \
int sha3_##bits(uint8_t* out, size_t outlen, \ int sha3_##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \ const uint8_t* in, size_t inlen) { \
if (outlen > (bits/8)) { \ if (outlen > (bits/8)) { \
return -1; \ return -1; \
} \ } \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
} }
/*** FIPS202 SHA3 FOFs ***/ /*** FIPS202 SHA3 FOFs ***/
defsha3(256) defsha3(256)
defsha3(512) defsha3(512)

6
sha3.h

@ -11,19 +11,19 @@ extern "C" {
struct ethash_h256; struct ethash_h256;
#define decsha3(bits) \ #define decsha3(bits) \
int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t);
decsha3(256) decsha3(256)
decsha3(512) decsha3(512)
static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const *data, const size_t size) static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const *data, const size_t size)
{ {
sha3_256((uint8_t*)ret, 32, data, size); sha3_256((uint8_t*)ret, 32, data, size);
} }
static inline void SHA3_512(uint8_t *ret, uint8_t const *data, const size_t size) static inline void SHA3_512(uint8_t *ret, uint8_t const *data, const size_t size)
{ {
sha3_512(ret, 64, data, size); sha3_512(ret, 64, data, size);
} }
#ifdef __cplusplus #ifdef __cplusplus

10
sha3_cryptopp.cpp

@ -25,11 +25,13 @@
extern "C" { extern "C" {
struct ethash_h256; struct ethash_h256;
typedef struct ethash_h256 ethash_h256_t; typedef struct ethash_h256 ethash_h256_t;
void SHA3_256(ethash_h256_t const* ret, const uint8_t *data, size_t size) { void SHA3_256(ethash_h256_t const* ret, const uint8_t *data, size_t size)
CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size); {
CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size);
} }
void SHA3_512(uint8_t *const ret, const uint8_t *data, size_t size) { void SHA3_512(uint8_t *const ret, const uint8_t *data, size_t size)
CryptoPP::SHA3_512().CalculateDigest(ret, data, size); {
CryptoPP::SHA3_512().CalculateDigest(ret, data, size);
} }
} }

2
util.c

@ -30,7 +30,7 @@ __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputStri
void debugf(const char *str, ...) void debugf(const char *str, ...)
{ {
va_list args; va_list args;
va_start(args, str); va_start(args, str);
char buf[1<<16]; char buf[1<<16];
_vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args); _vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args);

Loading…
Cancel
Save