diff --git a/multihashing.cc b/multihashing.cc index cede960f..6ccae254 100644 --- a/multihashing.cc +++ b/multihashing.cc @@ -144,6 +144,31 @@ NAN_METHOD(cryptonight_heavy) { info.GetReturnValue().Set(returnValue); } +NAN_METHOD(cryptonight_asc) { + if (info.Length() < 1) return THROW_ERROR_EXCEPTION("You must provide one argument."); + + Local target = info[0]->ToObject(); + if (!Buffer::HasInstance(target)) return THROW_ERROR_EXCEPTION("Argument 1 should be a buffer object."); + + int variant = 0; + + if (info.Length() >= 2) { + if (!info[1]->IsNumber()) return THROW_ERROR_EXCEPTION("Argument 2 should be a number"); + variant = Nan::To(info[1]).FromMaybe(0); + } + + char output[32]; + init_ctx(); + switch (variant) { + case 0: cryptonight_single_hash_asc(reinterpret_cast(Buffer::Data(target)), Buffer::Length(target), reinterpret_cast(output), &ctx); + break; + default: cryptonight_single_hash_asc(reinterpret_cast(Buffer::Data(target)), Buffer::Length(target), reinterpret_cast(output), &ctx); + } + + v8::Local returnValue = Nan::CopyBuffer(output, 32).ToLocalChecked(); + info.GetReturnValue().Set(returnValue); +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// class CCryptonightAsync : public Nan::AsyncWorker { @@ -360,6 +385,69 @@ NAN_METHOD(cryptonight_heavy_async) { Nan::AsyncQueueWorker(new CCryptonightHeavyAsync(callback, Buffer::Data(target), Buffer::Length(target), variant)); } +class CCryptonightAscAsync : public Nan::AsyncWorker { + + private: + + struct cryptonight_ctx* m_ctx; + const char* const m_input; + const uint32_t m_input_len; + const int m_variant; + char m_output[32]; + + public: + + CCryptonightAscAsync(Nan::Callback* const callback, const char* const input, const uint32_t input_len, const int variant) + : Nan::AsyncWorker(callback), m_ctx(static_cast(_mm_malloc(sizeof(cryptonight_ctx), 16))), + m_input(input), m_input_len(input_len), m_variant(variant) { + m_ctx->memory = static_cast(_mm_malloc(xmrig::CRYPTONIGHT_ASC_MEMORY, 4096)); + } + + ~CCryptonightAscAsync() { + _mm_free(m_ctx->memory); + _mm_free(m_ctx); + } + + void Execute () { + switch (m_variant) { + case 0: cryptonight_single_hash_asc(reinterpret_cast(m_input), m_input_len, reinterpret_cast(m_output), &m_ctx); + break; + default: cryptonight_single_hash_asc(reinterpret_cast(m_input), m_input_len, reinterpret_cast(m_output), &m_ctx); + } + } + + void HandleOKCallback () { + Nan::HandleScope scope; + + v8::Local argv[] = { + Nan::Null(), + v8::Local(Nan::CopyBuffer(m_output, 32).ToLocalChecked()) + }; + callback->Call(2, argv, async_resource); + } +}; + +NAN_METHOD(cryptonight_Asc_async) { + if (info.Length() < 2) return THROW_ERROR_EXCEPTION("You must provide at least two arguments."); + + Local target = info[0]->ToObject(); + if (!Buffer::HasInstance(target)) return THROW_ERROR_EXCEPTION("Argument should be a buffer object."); + + int variant = 0; + + int callback_arg_num; + if (info.Length() >= 3) { + if (!info[1]->IsNumber()) return THROW_ERROR_EXCEPTION("Argument 2 should be a number"); + variant = Nan::To(info[1]).FromMaybe(0); + callback_arg_num = 2; + } else { + callback_arg_num = 1; + } + + Callback *callback = new Nan::Callback(info[callback_arg_num].As()); + Nan::AsyncQueueWorker(new CCryptonightAscAsync(callback, Buffer::Data(target), Buffer::Length(target), variant)); +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -370,6 +458,8 @@ NAN_MODULE_INIT(init) { Nan::Set(target, Nan::New("cryptonight_light_async").ToLocalChecked(), Nan::GetFunction(Nan::New(cryptonight_light_async)).ToLocalChecked()); Nan::Set(target, Nan::New("cryptonight_heavy").ToLocalChecked(), Nan::GetFunction(Nan::New(cryptonight_heavy)).ToLocalChecked()); Nan::Set(target, Nan::New("cryptonight_heavy_async").ToLocalChecked(), Nan::GetFunction(Nan::New(cryptonight_heavy_async)).ToLocalChecked()); + Nan::Set(target, Nan::New("cryptonight_asc").ToLocalChecked(), Nan::GetFunction(Nan::New(cryptonight_asc)).ToLocalChecked()); + Nan::Set(target, Nan::New("cryptonight_asc_async").ToLocalChecked(), Nan::GetFunction(Nan::New(cryptonight_asc_async)).ToLocalChecked()); } NODE_MODULE(cryptonight, init) diff --git a/xmrig/common/xmrig.h b/xmrig/common/xmrig.h index 52650f0d..97fbac89 100644 --- a/xmrig/common/xmrig.h +++ b/xmrig/common/xmrig.h @@ -33,7 +33,8 @@ enum Algo { INVALID_ALGO = -1, CRYPTONIGHT, /* CryptoNight (Monero) */ CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */ - CRYPTONIGHT_HEAVY /* CryptoNight-Heavy (RYO) */ + CRYPTONIGHT_HEAVY, /* CryptoNight-Heavy (RYO) */ + CRYPTONIGHT_ASC /* CryptoNight-ASC (TAX) */ }; @@ -59,7 +60,7 @@ enum AlgoVariant { enum Variant { VARIANT_AUTO = -1, // Autodetect - VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy + VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy or CryptoNight-ASC VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) diff --git a/xmrig/crypto/CryptoNight_constants.h b/xmrig/crypto/CryptoNight_constants.h index f13891a7..67b37cd1 100644 --- a/xmrig/crypto/CryptoNight_constants.h +++ b/xmrig/crypto/CryptoNight_constants.h @@ -49,11 +49,16 @@ constexpr const size_t CRYPTONIGHT_HEAVY_MEMORY = 4 * 1024 * 1024; constexpr const uint32_t CRYPTONIGHT_HEAVY_MASK = 0x3FFFF0; constexpr const uint32_t CRYPTONIGHT_HEAVY_ITER = 0x40000; +constexpr const size_t CRYPTONIGHT_ASC_MEMORY = 2 * 1024 * 1024; +constexpr const uint32_t CRYPTONIGHT_ASC_MASK = 0x1FFFF0; +constexpr const uint32_t CRYPTONIGHT_ASC_ITER = 0x4000; -template inline constexpr size_t cn_select_memory() { return 0; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_LITE_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_HEAVY_MEMORY; } + +template inline constexpr size_t cn_select_memory() { return 0; } +template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_MEMORY; } +template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_LITE_MEMORY; } +template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_HEAVY_MEMORY; } +template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_ASC_MEMORY; } inline size_t cn_select_memory(Algo algorithm) @@ -69,6 +74,9 @@ inline size_t cn_select_memory(Algo algorithm) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_MEMORY; + case CRYPTONIGHT_ASC: + return CRYPTONIGHT_ASC_MEMORY; + default: break; } @@ -77,10 +85,11 @@ inline size_t cn_select_memory(Algo algorithm) } -template inline constexpr uint32_t cn_select_mask() { return 0; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_LITE_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_HEAVY_MASK; } +template inline constexpr uint32_t cn_select_mask() { return 0; } +template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_MASK; } +template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_LITE_MASK; } +template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_HEAVY_MASK; } +template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_ASC_MASK; } inline uint32_t cn_select_mask(Algo algorithm) @@ -96,6 +105,9 @@ inline uint32_t cn_select_mask(Algo algorithm) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_MASK; + case CRYPTONIGHT_ASC: + return CRYPTONIGHT_ASC_MASK; + default: break; } @@ -104,19 +116,20 @@ inline uint32_t cn_select_mask(Algo algorithm) } -template inline constexpr uint32_t cn_select_iter() { return 0; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_MSR_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_XAO_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } +template inline constexpr uint32_t cn_select_iter() { return 0; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_MSR_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_XAO_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ASC_ITER; } inline uint32_t cn_select_iter(Algo algorithm, Variant variant) @@ -143,6 +156,9 @@ inline uint32_t cn_select_iter(Algo algorithm, Variant variant) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_ITER; + case CRYPTONIGHT_ASC: + return CRYPTONIGHT_ASC_ITER; + default: break; } diff --git a/xmrig/crypto/CryptoNight_x86.h b/xmrig/crypto/CryptoNight_x86.h index 8dcdd414..feac3ec3 100644 --- a/xmrig/crypto/CryptoNight_x86.h +++ b/xmrig/crypto/CryptoNight_x86.h @@ -248,7 +248,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) xin6 = _mm_load_si128(input + 10); xin7 = _mm_load_si128(input + 11); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_ASC) { for (size_t i = 0; i < 16; i++) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -328,12 +328,12 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_ASC) { mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); } } - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_ASC) { for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); @@ -449,6 +449,78 @@ static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, } } +template +inline void cryptonight_single_hash_asc(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +{ + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + + if (IS_V1 && size < 43) { + memset(output, 0, 32); + return; + } + if (VARIANT == xmrig::VARIANT_ASC) { + + hash_process(&ctx->state.hs, (const uint8_t*) input, len); + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + memcpy(ctx->aes_key, ctx->state.hs.b, FD_SETSIZE); + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); + size_t i, j; + + VARIANT1_INIT(); + + oaes_key_import_data(ctx->aes_ctx, ctx->aes_key, AES_KEY_SIZE); + for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) { + for (j = 0; j < INIT_SIZE_BLK; j++) { + aesb_pseudo_round(&ctx->text[AES_BLOCK_SIZE * j], + &ctx->text[AES_BLOCK_SIZE * j], + ctx->aes_ctx->key->exp_data); + } + memcpy(&ctx->long_state[i * INIT_SIZE_BYTE], ctx->text, INIT_SIZE_BYTE); + } + + for (i = 0; i < 16; i++) { + ctx->a[i] = ctx->state.k[i] ^ ctx->state.k[32 + i]; + ctx->b[i] = ctx->state.k[16 + i] ^ ctx->state.k[48 + i]; + } + + for (i = 0; i < ITER / 2; i++) { + /* Dependency chain: address -> read value ------+ + * written value <-+ hard function (AES or MUL) <+ + * next address <-+ + */ + /* Iteration 1 */ + j = e2i(ctx->a); + aesb_single_round(&ctx->long_state[j * AES_BLOCK_SIZE], ctx->c, ctx->a); + xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j * AES_BLOCK_SIZE]); + VARIANT1_1((uint8_t*)&ctx->long_state[j * AES_BLOCK_SIZE]); + /* Iteration 2 */ + mul_sum_xor_dst(ctx->c, ctx->a, + &ctx->long_state[e2i(ctx->c) * AES_BLOCK_SIZE]); + copy_block(ctx->b, ctx->c); + + } + + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE); + for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) { + for (j = 0; j < INIT_SIZE_BLK; j++) { + xor_blocks(&ctx->text[j * AES_BLOCK_SIZE], + &ctx->long_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]); + aesb_pseudo_round(&ctx->text[j * AES_BLOCK_SIZE], + &ctx->text[j * AES_BLOCK_SIZE], + ctx->aes_ctx->key->exp_data); + } + } + memcpy(ctx->state.init, ctx->text, INIT_SIZE_BYTE); + hash_permutation(&ctx->state.hs); + /*memcpy(hash, &state, 32);*/ + extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); + oaes_free((OAES_CTX **) &ctx->aes_ctx); +} + template inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) @@ -553,7 +625,8 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si } bx0 = cx; } - + + cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); xmrig::keccakf(h0, 24);