Skip to content

Commit

Permalink
update based on reference ProgPoW from ethereum/EIPs#1589
Browse files Browse the repository at this point in the history
  • Loading branch information
hackmod committed Nov 30, 2018
1 parent 3d675b3 commit ee45d3f
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/libethash/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ ethash_return_value_t ethash_light_compute_internal(
);

void keccak_f800_round(uint32_t st[25], const int r);
uint64_t keccak_f800(hash32_t header, uint64_t seed, uint32_t *result);
hash32_t keccak_f800_progpow(hash32_t header, uint64_t seed, hash32_t digest);
uint32_t progpowMath(uint32_t a, uint32_t b, uint32_t r);
void merge(uint32_t *a, uint32_t b, uint32_t r);

Expand Down
43 changes: 24 additions & 19 deletions src/libethash/progpow-internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ void keccak_f800_round(uint32_t st[25], const int r)

// Implementation of the Keccak sponge construction (with padding omitted)
// The width is 800, with a bitrate of 576, and a capacity of 224.
uint64_t keccak_f800(hash32_t header, uint64_t seed, uint32_t *result)
hash32_t keccak_f800_progpow(hash32_t header, uint64_t seed, hash32_t digest)
{
uint32_t st[25];

Expand All @@ -187,19 +187,20 @@ uint64_t keccak_f800(hash32_t header, uint64_t seed, uint32_t *result)
st[8] = seed;
st[9] = seed >> 32;
for (int i = 0; i < 8; i++)
st[10+i] = result[i];
st[10+i] = digest.uint32s[i];

for (int r = 0; r < 21; r++) {
keccak_f800_round(st, r);
}
// last round can be simplified due to partial output
keccak_f800_round(st, 21);

for (int i = 0; i < 8; ++i) {
result[i] = st[i];
hash32_t ret;
for (int i = 0; i < 8; i++) {
ret.uint32s[i] = st[i];
}

return (uint64_t)ethash_swap_u32(st[0]) << 32 | ethash_swap_u32(st[1]);
return ret;
}

typedef struct {
Expand All @@ -211,12 +212,14 @@ typedef struct {
// http://www.cse.yorku.ca/~oz/marsaglia-rng.html
uint32_t kiss99(kiss99_t * st)
{
uint32_t znew = (st->z = 36969 * (st->z & 65535) + (st->z >> 16));
uint32_t wnew = (st->w = 18000 * (st->w & 65535) + (st->w >> 16));
uint32_t MWC = ((znew << 16) + wnew);
uint32_t SHR3 = (st->jsr ^= (st->jsr << 17), st->jsr ^= (st->jsr >> 13), st->jsr ^= (st->jsr << 5));
uint32_t CONG = (st->jcong = 69069 * st->jcong + 1234567);
return ((MWC^CONG) + SHR3);
st->z = 36969 * (st->z & 65535) + (st->z >> 16);
st->w = 18000 * (st->w & 65535) + (st->w >> 16);
uint32_t MWC = ((st->z << 16) + st->w);
st->jsr ^= (st->jsr << 17);
st->jsr ^= (st->jsr >> 13);
st->jsr ^= (st->jsr << 5);
st->jcong = 69069 * st->jcong + 1234567;
return ((MWC^st->jcong) + st->jsr);
}

void fill_mix(
Expand Down Expand Up @@ -438,12 +441,14 @@ static bool progpow_hash(
}

uint32_t mix[PROGPOW_LANES][PROGPOW_REGS];
uint32_t result[8];
hash32_t digest;
for (int i = 0; i < 8; i++)
result[i] = 0;
digest.uint32s[i] = 0;

// keccak(header..nonce)
uint64_t seed = keccak_f800(header, nonce, result);
hash32_t seed_256 = keccak_f800_progpow(header, nonce, digest);
// endian swap so byte 0 of the hash is the MSB of the value
uint64_t seed = (uint64_t)ethash_swap_u32(seed_256.uint32s[0]) << 32 | ethash_swap_u32(seed_256.uint32s[1]);

// initialize mix for all lanes
for (int l = 0; l < PROGPOW_LANES; l++)
Expand All @@ -467,16 +472,16 @@ static bool progpow_hash(
}
// Reduce all lanes to a single 256-bit result
for (int i = 0; i < 8; i++)
result[i] = 0x811c9dc5;
digest.uint32s[i] = 0x811c9dc5;

for (int l = 0; l < PROGPOW_LANES; l++)
fnv1a(&result[l%8], lane_hash[l]);
fnv1a(&digest.uint32s[l%8], lane_hash[l]);

memset((void *)&ret->mix_hash, 0, sizeof(ret->mix_hash));
memcpy(&ret->mix_hash, result, sizeof(result));
memcpy(&ret->mix_hash, (void *)&digest, sizeof(digest));
memset((void *)&ret->result, 0, sizeof(ret->result));
keccak_f800(header, seed, result);
memcpy((void *)&ret->result, (void *)&result, sizeof(ret->result));
digest = keccak_f800_progpow(header, seed, digest);
memcpy((void *)&ret->result, (void *)&digest, sizeof(ret->result));

return true;
}
Expand Down
11 changes: 6 additions & 5 deletions test/c/test_progpow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,21 +213,22 @@ BOOST_AUTO_TEST_CASE(test_progpow_keccak_f800) {
const std::string header_string = blockhashToHexString(&headerhash);
BOOST_REQUIRE_MESSAGE(true,
"\nheader: " << header_string.c_str() << "\n");
uint32_t result[8];
hash32_t result;
for (int i = 0; i < 8; i++)
result[i] = 0;
result.uint32s[i] = 0;

hash32_t header;
memcpy((void *)&header, (void *)&headerhash, sizeof(headerhash));
uint64_t nonce = 0x0;
// keccak(header..nonce)
uint64_t seed = keccak_f800(header, nonce, result);
hash32_t seed_256 = keccak_f800_progpow(header, nonce, result);
uint64_t seed = (uint64_t)ethash_swap_u32(seed_256.uint32s[0]) << 32 | ethash_swap_u32(seed_256.uint32s[1]);
uint64_t exp = 0x5dd431e5fbc604f4U;

BOOST_REQUIRE_MESSAGE(seed == exp,
"\nseed: " << seed << "\n");
"\nseed: " << seed << "exp: " << exp << "\n");
ethash_h256_t out;
memcpy((void *)&out, (void *)&result, sizeof(result));
memcpy((void *)&out, (void *)&seed_256, sizeof(result));
const std::string out_string = blockhashToHexString(&out);
BOOST_REQUIRE_MESSAGE(out_string == seedexp,
"\nresult: " << out_string.c_str() << "\n");
Expand Down

0 comments on commit ee45d3f

Please sign in to comment.