From 14e831d12554125c36de21223b6bdd0712f745e7 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Thu, 22 Feb 2018 00:42:03 -0500 Subject: [PATCH] Monero cryptonight variant, version 1 --- cpu-miner.c | 34 ++++++++++++++++++++++++++-------- cryptonight.h | 18 +++++++++++++++++- cryptonight_aesni.c | 9 +++++++-- cryptonight_common.c | 15 +++++++++------ cryptonight_lobotomized.c | 15 ++++++++++----- miner.h | 2 +- 6 files changed, 70 insertions(+), 23 deletions(-) diff --git a/cpu-miner.c b/cpu-miner.c index 65252846..691d4ab4 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -120,6 +120,7 @@ enum mining_algo { ALGO_BLAKE, /* Blake */ ALGO_X11, /* X11 */ ALGO_CRYPTONIGHT, /* CryptoNight */ + ALGO_CRYPTONIGHT_MONERO, /* CryptoNight with Monero tweaks */ }; static const char *algo_names[] = { @@ -133,6 +134,7 @@ static const char *algo_names[] = { [ALGO_BLAKE] = "blake", [ALGO_X11] = "x11", [ALGO_CRYPTONIGHT] = "cryptonight", + [ALGO_CRYPTONIGHT_MONERO] = "cryptonight-monero", }; bool opt_debug = false; @@ -155,7 +157,7 @@ int opt_timeout = 0; static int opt_scantime = 5; static json_t *opt_config; static const bool opt_time = true; -static enum mining_algo opt_algo = ALGO_CRYPTONIGHT; +static enum mining_algo opt_algo = ALGO_CRYPTONIGHT_MONERO; static int opt_n_threads; static int num_processors; static char *rpc_url; @@ -545,6 +547,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, @@ -571,6 +574,7 @@ static bool submit_upstream_work(CURL *curl, struct work *work) { char s[BIG_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)) { @@ -582,14 +586,20 @@ static bool submit_upstream_work(CURL *curl, struct work *work) { if (have_stratum) { uint32_t ntime, nonce; char *ntimestr, *noncestr, *xnonce2str; + 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, work->dlen); + if (!cryptonight_hash(hash, work->data, work->dlen, variant)) { + applog(LOG_ERR, "submit_upstream_work cryptonight_hash failed"); + goto out; + } } char *hashhex = bin2hex(hash, 32); snprintf(s, JSON_BUF_LEN, @@ -615,6 +625,7 @@ static bool submit_upstream_work(CURL *curl, struct work *work) { goto out; } } else if (have_daemon) { + int variant = is_monero && ((const unsigned char*)work->data)[0] >= 7 ? ((const unsigned char*)work->data)[0] - 6 : 0; char *noncestr; time_t work_time; pthread_mutex_lock(&g_work_lock); @@ -654,12 +665,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, work->dlen); + if (!cryptonight_hash(hash, work->data, work->dlen, variant)) { + applog(LOG_ERR, "submit_upstream_work cryptonight_hash failed"); + goto out; + } } char *hashhex = bin2hex(hash, 32); snprintf(s, JSON_BUF_LEN, @@ -1090,7 +1106,7 @@ static void *miner_thread(void *userdata) { }*/ persistentctx = persistentctxs[thr_id]; - if(!persistentctx && opt_algo == ALGO_CRYPTONIGHT) + if(!persistentctx && (opt_algo == ALGO_CRYPTONIGHT || opt_algo == ALGO_CRYPTONIGHT_MONERO)) { #if defined __unix__ && (!defined __APPLE__) && (!defined DISABLE_LINUX_HUGEPAGES) persistentctx = (struct cryptonight_ctx *)mmap(0, sizeof(struct cryptonight_ctx), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0); @@ -1167,7 +1183,7 @@ static void *miner_thread(void *userdata) { max64 = 0xfffLL; break; case ALGO_CRYPTONIGHT: - + case ALGO_CRYPTONIGHT_MONERO: max64 = 0x40LL; break; default: @@ -1199,6 +1215,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; @@ -1217,6 +1234,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: @@ -1887,7 +1905,7 @@ static void signal_handler(int sig) { case SIGINT: applog(LOG_INFO, "SIGINT received, exiting"); #if defined __unix__ && (!defined __APPLE__) - if(opt_algo == ALGO_CRYPTONIGHT) + if(opt_algo == ALGO_CRYPTONIGHT || opt_algo == ALGO_CRYPTONIGHT_MONERO) for(i = 0; i < opt_n_threads; i++) munmap(persistentctxs[i], sizeof(struct cryptonight_ctx)); #endif exit(0); @@ -1895,7 +1913,7 @@ static void signal_handler(int sig) { case SIGTERM: applog(LOG_INFO, "SIGTERM received, exiting"); #if defined __unix__ && (!defined __APPLE__) - if(opt_algo == ALGO_CRYPTONIGHT) + if(opt_algo == ALGO_CRYPTONIGHT || opt_algo == ALGO_CRYPTONIGHT_MONERO) for(i = 0; i < opt_n_threads; i++) munmap(persistentctxs[i], sizeof(struct cryptonight_ctx)); #endif exit(0); @@ -2115,7 +2133,7 @@ int main(int argc, char *argv[]) { applog(LOG_INFO, "workio thread dead, exiting."); #if defined __unix__ && (!defined __APPLE__) - if(opt_algo == ALGO_CRYPTONIGHT) + if(opt_algo == ALGO_CRYPTONIGHT || opt_algo == ALGO_CRYPTONIGHT_MONERO) for(i = 0; i < opt_n_threads; i++) munmap(persistentctxs[i], sizeof(struct cryptonight_ctx)); #endif return 0; diff --git a/cryptonight.h b/cryptonight.h index 9e7c5683..60733aa6 100644 --- a/cryptonight.h +++ b/cryptonight.h @@ -60,9 +60,25 @@ void do_groestl_hash(const void* input, size_t len, char* output); void do_jh_hash(const void* input, size_t len, char* output); void do_skein_hash(const void* input, size_t len, char* output); void xor_blocks_dst(const uint8_t *restrict a, const uint8_t *restrict b, uint8_t *restrict dst); -void cryptonight_hash_ctx(void* output, const void* input, int inlen, struct cryptonight_ctx* ctx); +int cryptonight_hash_ctx(void* output, const void* input, int inlen, struct cryptonight_ctx* ctx, int variant); void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen); void keccakf(uint64_t st[25], int rounds); extern void (* const extra_hashes[4])(const void *, size_t, char *); +#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_INIT() \ + if (variant > 0 && inlen < 43) \ + { \ + return 0; \ + } \ + const uint64_t tweak1_2 = variant > 0 ? *((const uint64_t*) (((const uint8_t*)input) + 35)) ^ ctx->state.hs.w[24] : 0 + #endif diff --git a/cryptonight_aesni.c b/cryptonight_aesni.c index 67e4d07d..09cc7413 100644 --- a/cryptonight_aesni.c +++ b/cryptonight_aesni.c @@ -85,12 +85,14 @@ static inline void ExpandAESKey256(char *keybuf) keys[14] = tmp1; } -void cryptonight_hash_ctx(void *restrict output, const void *restrict input, int inlen, struct cryptonight_ctx *restrict ctx) +int cryptonight_hash_ctx(void *restrict output, const void *restrict input, int inlen, struct cryptonight_ctx *restrict ctx, int variant) { keccak((const uint8_t *)input, inlen, &ctx->state.hs, 200); uint8_t ExpandedKey[256]; size_t i, j; + VARIANT1_INIT(); + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); memcpy(ExpandedKey, ctx->state.hs.b, AES_KEY_SIZE); ExpandAESKey256(ExpandedKey); @@ -150,6 +152,8 @@ void cryptonight_hash_ctx(void *restrict output, const void *restrict input, int b_x = _mm_xor_si128(b_x, c_x); _mm_store_si128((__m128i *)&ctx->long_state[a[0] & 0x1FFFF0], b_x); + VARIANT1_1(&ctx->long_state[a[0] & 0x1FFFF0]); + uint64_t *nextblock = (uint64_t *)&ctx->long_state[c[0] & 0x1FFFF0]; uint64_t b[2]; b[0] = nextblock[0]; @@ -171,7 +175,7 @@ void cryptonight_hash_ctx(void *restrict output, const void *restrict input, int } uint64_t *dst = &ctx->long_state[c[0] & 0x1FFFF0]; dst[0] = a[0]; - dst[1] = a[1]; + dst[1] = variant > 0 ? a[1] ^ tweak1_2 : a[1]; a[0] ^= b[0]; a[1] ^= b[1]; @@ -214,4 +218,5 @@ void cryptonight_hash_ctx(void *restrict output, const void *restrict input, int memcpy(ctx->state.init, ctx->text, INIT_SIZE_BYTE); keccakf(&ctx->state.hs, 24); extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); + return 1; } diff --git a/cryptonight_common.c b/cryptonight_common.c index 8dfa4f67..f0ea8dfc 100644 --- a/cryptonight_common.c +++ b/cryptonight_common.c @@ -41,14 +41,16 @@ void xor_blocks_dst(const uint8_t *restrict a, const uint8_t *restrict b, uint8_ void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash}; -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); + int rc = cryptonight_hash_ctx(output, input, len, ctx, variant); free(ctx); + return rc; } int scanhash_cryptonight(int thr_id, uint32_t *restrict pdata, int dlen, const uint32_t *restrict ptarget, uint32_t max_nonce, unsigned long *restrict hashes_done, struct cryptonight_ctx *persistentctx) { uint32_t *nonceptr = (uint32_t*) (((char*)pdata) + 39); + int variant = ((const unsigned char*)pdata)[0] >= 7 ? ((const unsigned char*)pdata)[0] - 6 : 0; uint32_t n = *nonceptr - 1; const uint32_t first_nonce = n + 1; const uint64_t Htarg = ((const uint64_t *)ptarget)[3]; @@ -56,10 +58,11 @@ int scanhash_cryptonight(int thr_id, uint32_t *restrict pdata, int dlen, const u do { *nonceptr = ++n; - cryptonight_hash_ctx(hash, pdata, dlen, persistentctx); - if (unlikely(hash[3] < Htarg)) { - *hashes_done = n - first_nonce + 1; - return true; + if (cryptonight_hash_ctx(hash, pdata, dlen, persistentctx, variant)) { + if (unlikely(hash[3] < Htarg)) { + *hashes_done = n - first_nonce + 1; + return true; + } } } while (likely((n <= max_nonce && !work_restart[thr_id].restart))); diff --git a/cryptonight_lobotomized.c b/cryptonight_lobotomized.c index 9d4d4508..1498e386 100644 --- a/cryptonight_lobotomized.c +++ b/cryptonight_lobotomized.c @@ -189,7 +189,7 @@ static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64 return product_lo; } -static inline void mul_sum_xor_dst(const uint8_t *a, uint8_t *c, uint8_t *dst) +static inline void mul_sum_xor_dst(const uint8_t *a, uint8_t *c, uint8_t *dst, int variant, const uint64_t tweak1_2) { uint64_t hi, lo = mul128(((uint64_t *)a)[0], ((uint64_t *)dst)[0], &hi) + ((uint64_t *)c)[1]; hi += ((uint64_t *)c)[0]; @@ -197,7 +197,7 @@ static inline void mul_sum_xor_dst(const uint8_t *a, uint8_t *c, uint8_t *dst) ((uint64_t *)c)[0] = ((uint64_t*) dst)[0] ^ hi; ((uint64_t *)c)[1] = ((uint64_t*) dst)[1] ^ lo; ((uint64_t *)dst)[0] = hi; - ((uint64_t *)dst)[1] = lo; + ((uint64_t *)dst)[1] = variant > 0 ? lo ^ tweak1_2 : lo; } static inline void xor_blocks(uint8_t *restrict a, const uint8_t *restrict b) { @@ -205,13 +205,15 @@ static inline void xor_blocks(uint8_t *restrict a, const uint8_t *restrict b) { ((uint64_t*) a)[1] ^= ((uint64_t*) b)[1]; } -void cryptonight_hash_ctx(void *restrict output, const void *restrict input, int inlen, struct cryptonight_ctx *restrict ctx) { +int cryptonight_hash_ctx(void *restrict output, const void *restrict input, int inlen, struct cryptonight_ctx *restrict ctx, int variant) { ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); size_t i, j; //hash_process(&ctx->state.hs, (const uint8_t*) input, 76); keccak((const uint8_t *)input, inlen, &ctx->state.hs, 200); 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); @@ -248,13 +250,15 @@ void cryptonight_hash_ctx(void *restrict output, const void *restrict input, int // Iteration 1 SubAndShiftAndMixAddRound(ctx->c, &ctx->long_state[((uint64_t *)(ctx->a))[0] & 0x1FFFF0], ctx->a); xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[((uint64_t *)(ctx->a))[0] & 0x1FFFF0]); + VARIANT1_1(&ctx->long_state[((uint64_t *)(ctx->a))[0] & 0x1FFFF0]); // Iteration 2 - mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[((uint64_t *)(ctx->c))[0] & 0x1FFFF0]); + mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[((uint64_t *)(ctx->c))[0] & 0x1FFFF0], variant, tweak1_2); // Iteration 3 SubAndShiftAndMixAddRound(ctx->b, &ctx->long_state[((uint64_t *)(ctx->a))[0] & 0x1FFFF0], ctx->a); xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[((uint64_t *)(ctx->a))[0] & 0x1FFFF0]); + VARIANT1_1(&ctx->long_state[((uint64_t *)(ctx->a))[0] & 0x1FFFF0]); // Iteration 4 - mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[((uint64_t *)(ctx->b))[0] & 0x1FFFF0]); + mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[((uint64_t *)(ctx->b))[0] & 0x1FFFF0], variant, tweak1_2); } memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); @@ -290,4 +294,5 @@ void cryptonight_hash_ctx(void *restrict output, const void *restrict input, int /*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; } diff --git a/miner.h b/miner.h index 932d5230..1cf6f247 100644 --- a/miner.h +++ b/miner.h @@ -182,7 +182,7 @@ extern int scanhash_blake(int thr_id, uint32_t *pdata, const uint32_t *ptarget, extern int scanhash_x11(int thr_id, uint32_t *pdata, const uint32_t *ptarget, uint32_t max_nonce, unsigned long *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, int dlen, const uint32_t *ptarget, uint32_t max_nonce, unsigned long *hashes_done, struct cryptonight_ctx *persistentctx);