From d7543505705d2dc766abe36619acdce967f8da0f Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Thu, 1 Mar 2018 16:17:59 -0500 Subject: [PATCH] updates for the monero-v1 pow tweaks --- cpu-miner.c | 27 ++++++++++++++++++++++--- cryptonight.c | 55 +++++++++++++++++++++++++++++++++++++++++++-------- miner.h | 2 +- 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/cpu-miner.c b/cpu-miner.c index 1652a281f..c2c47233a 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -114,6 +114,7 @@ enum algos { ALGO_X14, /* X14 */ ALGO_X15, /* X15 Whirlpool */ ALGO_CRYPTONIGHT, /* CryptoNight */ + ALGO_CRYPTONIGHT_MONERO, /* CryptoNight with Monero tweaks */ }; static const char *algo_names[] = { @@ -131,6 +132,7 @@ static const char *algo_names[] = { [ALGO_X14] = "x14", [ALGO_X15] = "x15", [ALGO_CRYPTONIGHT] = "cryptonight", + [ALGO_CRYPTONIGHT_MONERO] = "cryptonight-monero", }; bool opt_debug = false; @@ -215,6 +217,7 @@ Options:\n\ x14 X14\n\ x15 X15\n\ cryptonight CryptoNight\n\ + cryptonight-monero CryptoNight with Monero variants\n\ -o, --url=URL URL of mining server\n\ -O, --userpass=U:P username:password pair for mining server\n\ -u, --user=USERNAME username for mining server\n\ @@ -560,6 +563,7 @@ static void share_result(int result, struct work *work, const char *reason) { switch (opt_algo) { case ALGO_CRYPTONIGHT: + case ALGO_CRYPTONIGHT_MONERO: applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %.2f H/s at diff %g %s", accepted_count, accepted_count + rejected_count, 100. * accepted_count / (accepted_count + rejected_count), hashrate, @@ -585,6 +589,7 @@ static bool submit_upstream_work(CURL *curl, struct work *work) { char s[JSON_BUF_LEN]; int i; bool rc = false; + bool is_monero = opt_algo == ALGO_CRYPTONIGHT_MONERO; /* pass if the previous hash is not the current previous hash */ if (!submit_old && memcmp(work->data + 1, g_work.data + 1, 32)) { @@ -596,14 +601,21 @@ static bool submit_upstream_work(CURL *curl, struct work *work) { if (have_stratum) { uint32_t ntime, nonce; char *ntimestr, *noncestr, *xnonce2str; + bool is_monero = opt_algo == ALGO_CRYPTONIGHT_MONERO; + int variant; if (jsonrpc_2) { + variant = is_monero && ((const unsigned char*)work->data)[0] >= 7 ? ((const unsigned char*)work->data)[0] - 6 : 0; noncestr = bin2hex(((const unsigned char*)work->data) + 39, 4); char hash[32]; switch(opt_algo) { case ALGO_CRYPTONIGHT: + case ALGO_CRYPTONIGHT_MONERO: default: - cryptonight_hash(hash, work->data, 76); + if (!cryptonight_hash(hash, work->data, 76, variant)) { + applog(LOG_ERR, "submit_upstream_work cryptonight_hash failed"); + goto out; + } } char *hashhex = bin2hex(hash, 32); snprintf(s, JSON_BUF_LEN, @@ -631,12 +643,17 @@ static bool submit_upstream_work(CURL *curl, struct work *work) { } else { /* build JSON-RPC request */ if(jsonrpc_2) { + int variant = is_monero && ((const unsigned char*)work->data)[0] >= 7 ? ((const unsigned char*)work->data)[0] - 6 : 0; char *noncestr = bin2hex(((const unsigned char*)work->data) + 39, 4); char hash[32]; switch(opt_algo) { case ALGO_CRYPTONIGHT: + case ALGO_CRYPTONIGHT_MONERO: default: - cryptonight_hash(hash, work->data, 76); + if (!cryptonight_hash(hash, work->data, 76, variant)) { + applog(LOG_ERR, "submit_upstream_work cryptonight_hash failed"); + goto out; + } } char *hashhex = bin2hex(hash, 32); snprintf(s, JSON_BUF_LEN, @@ -1128,6 +1145,7 @@ static void *miner_thread(void *userdata) { max64 = opt_scrypt_n < 16 ? 0x3ffff : 0x3fffff / opt_scrypt_n; break; case ALGO_CRYPTONIGHT: + case ALGO_CRYPTONIGHT_MONERO: max64 = 0x40LL; break; case ALGO_FRESH: @@ -1215,6 +1233,7 @@ static void *miner_thread(void *userdata) { &hashes_done); break; case ALGO_CRYPTONIGHT: + case ALGO_CRYPTONIGHT_MONERO: rc = scanhash_cryptonight(thr_id, work.data, work.target, max_nonce, &hashes_done); break; @@ -1236,6 +1255,7 @@ static void *miner_thread(void *userdata) { if (!opt_quiet) { switch(opt_algo) { case ALGO_CRYPTONIGHT: + case ALGO_CRYPTONIGHT_MONERO: applog(LOG_INFO, "thread %d: %lu hashes, %.2f H/s", thr_id, hashes_done, thr_hashrates[thr_id]); break; @@ -1254,6 +1274,7 @@ static void *miner_thread(void *userdata) { if (i == opt_n_threads) { switch(opt_algo) { case ALGO_CRYPTONIGHT: + case ALGO_CRYPTONIGHT_MONERO: applog(LOG_INFO, "Total: %s H/s", hashrate); break; default: @@ -1852,7 +1873,7 @@ int main(int argc, char *argv[]) { init_quarkhash_contexts(); } else if (opt_algo == ALGO_BLAKE) { init_blakehash_contexts(); - } else if(opt_algo == ALGO_CRYPTONIGHT) { + } else if(opt_algo == ALGO_CRYPTONIGHT || opt_algo == ALGO_CRYPTONIGHT_MONERO) { jsonrpc_2 = true; aes_ni_supported = has_aes_ni(); applog(LOG_INFO, "Using JSON-RPC 2.0"); diff --git a/cryptonight.c b/cryptonight.c index 43bcef7df..6deba7563 100644 --- a/cryptonight.c +++ b/cryptonight.c @@ -32,6 +32,29 @@ typedef __uint128_t uint128_t; #define INIT_SIZE_BLK 8 #define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE) +#define VARIANT1_1(p) \ + do if (variant > 0) \ + { \ + const uint8_t tmp = ((const uint8_t*)(p))[11]; \ + static const uint32_t table = 0x75310; \ + const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ + ((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \ + } while(0) + +#define VARIANT1_2(p) \ + do if (variant > 0) \ + { \ + ((uint64_t*)p)[1] ^= tweak1_2; \ + } while(0) + +#define VARIANT1_INIT() \ + if (variant > 0 && len < 43) \ + { \ + return 0; \ + } \ + const uint64_t tweak1_2 = variant > 0 ? *(const uint64_t*)(((const uint8_t*)input)+35) ^ ctx->state.hs.w[24] : 0 + + #pragma pack(push, 1) union cn_slow_hash_state { union hash_state hs; @@ -112,12 +135,14 @@ struct cryptonight_ctx { oaes_ctx* aes_ctx; }; -void cryptonight_hash_ctx(void* output, const void* input, size_t len, struct cryptonight_ctx* ctx) { +int cryptonight_hash_ctx(void* output, const void* input, size_t len, struct cryptonight_ctx* ctx, int variant) { hash_process(&ctx->state.hs, (const uint8_t*) input, len); ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); size_t i, j; memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + VARIANT1_INIT(); + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 0], ctx->aes_ctx->key->exp_data); @@ -143,14 +168,18 @@ void cryptonight_hash_ctx(void* output, const void* input, size_t len, struct cr j = e2i(ctx->a); aesb_single_round(&ctx->long_state[j], ctx->c, ctx->a); xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); + VARIANT1_1(&ctx->long_state[j]); /* Iteration 2 */ mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)]); + VARIANT1_2(&ctx->long_state[e2i(ctx->c)]); /* Iteration 3 */ j = e2i(ctx->a); aesb_single_round(&ctx->long_state[j], ctx->b, ctx->a); xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); + VARIANT1_1(&ctx->long_state[j]); /* Iteration 4 */ mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)]); + VARIANT1_2(&ctx->long_state[e2i(ctx->b)]); } memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); @@ -178,20 +207,24 @@ void cryptonight_hash_ctx(void* output, const void* input, size_t len, struct cr /*memcpy(hash, &state, 32);*/ extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); oaes_free((OAES_CTX **) &ctx->aes_ctx); + return 1; } -void cryptonight_hash(void* output, const void* input, size_t len) { +int cryptonight_hash(void* output, const void* input, size_t len, int variant) { struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); - cryptonight_hash_ctx(output, input, len, ctx); + const int rc = cryptonight_hash_ctx(output, input, len, ctx, variant); free(ctx); + return rc; } -void cryptonight_hash_ctx_aes_ni(void* output, const void* input, size_t len, struct cryptonight_ctx* ctx) { +int cryptonight_hash_ctx_aes_ni(void* output, const void* input, size_t len, struct cryptonight_ctx* ctx, int variant) { hash_process(&ctx->state.hs, (const uint8_t*) input, len); ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); size_t i, j; memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + VARIANT1_INIT(); + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 0], ctx->aes_ctx->key->exp_data); @@ -217,14 +250,18 @@ void cryptonight_hash_ctx_aes_ni(void* output, const void* input, size_t len, st j = e2i(ctx->a); fast_aesb_single_round(&ctx->long_state[j], ctx->c, ctx->a); xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); + VARIANT1_1(&ctx->long_state[j]); /* Iteration 2 */ mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)]); + VARIANT1_2(&ctx->long_state[j]); /* Iteration 3 */ j = e2i(ctx->a); fast_aesb_single_round(&ctx->long_state[j], ctx->b, ctx->a); xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); + VARIANT1_1(&ctx->long_state[j]); /* Iteration 4 */ mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)]); + VARIANT1_2(&ctx->long_state[j]); } memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); @@ -252,12 +289,14 @@ void cryptonight_hash_ctx_aes_ni(void* output, const void* input, size_t len, st /*memcpy(hash, &state, 32);*/ extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); oaes_free((OAES_CTX **) &ctx->aes_ctx); + return 1; } int scanhash_cryptonight(int thr_id, uint32_t *pdata, const uint32_t *ptarget, uint32_t max_nonce, uint64_t *hashes_done) { uint32_t *nonceptr = (uint32_t*) (((char*)pdata) + 39); uint32_t n = *nonceptr - 1; + int variant = ((const unsigned char*)pdata)[0] >= 7 ? ((const unsigned char*)pdata)[0] - 6 : 0; const uint32_t first_nonce = n + 1; const uint32_t Htarg = ptarget[7]; uint32_t hash[HASH_SIZE / 4] __attribute__((aligned(32))); @@ -267,8 +306,8 @@ int scanhash_cryptonight(int thr_id, uint32_t *pdata, const uint32_t *ptarget, if (aes_ni_supported) { do { *nonceptr = ++n; - cryptonight_hash_ctx_aes_ni(hash, pdata, 76, ctx); - if (unlikely(hash[7] < ptarget[7])) { + const int rc = cryptonight_hash_ctx_aes_ni(hash, pdata, 76, ctx, variant); + if (likely(rc) && unlikely(hash[7] < ptarget[7])) { *hashes_done = n - first_nonce + 1; free(ctx); return true; @@ -277,8 +316,8 @@ int scanhash_cryptonight(int thr_id, uint32_t *pdata, const uint32_t *ptarget, } else { do { *nonceptr = ++n; - cryptonight_hash_ctx(hash, pdata, 76, ctx); - if (unlikely(hash[7] < ptarget[7])) { + const int rc = cryptonight_hash_ctx(hash, pdata, 76, ctx, variant); + if (likely(rc) && unlikely(hash[7] < ptarget[7])) { *hashes_done = n - first_nonce + 1; free(ctx); return true; diff --git a/miner.h b/miner.h index bc77a1f4d..3aff700f1 100644 --- a/miner.h +++ b/miner.h @@ -194,7 +194,7 @@ extern int scanhash_x14(int thr_id, uint32_t *pdata, const uint32_t *ptarget, extern int scanhash_x15(int thr_id, uint32_t *pdata, const uint32_t *ptarget, uint32_t max_nonce, uint64_t *hashes_done); -extern void cryptonight_hash(void* output, const void* input, size_t input_len); +extern int cryptonight_hash(void* output, const void* input, size_t input_len, int variant); extern int scanhash_cryptonight(int thr_id, uint32_t *pdata, const uint32_t *ptarget, uint32_t max_nonce, uint64_t *hashes_done);