diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d993dda8..5f34e2346 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ set(HEADERS_CRYPTO src/crypto/c_skein.h src/crypto/CryptoNight.h src/crypto/CryptoNight_p.h + src/crypto/CryptoNight_test.h src/crypto/groestl_tables.h src/crypto/hash.h src/crypto/skein_port.h diff --git a/src/Options.cpp b/src/Options.cpp index 1fbdb1419..11f01d00d 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -178,6 +178,10 @@ Options::Options(int argc, char **argv) : m_pass = strdup("x"); } + if (m_algoVariant == AV2_AESNI_DOUBLE || m_algoVariant == AV4_SOFT_AES_DOUBLE) { + m_doubleHash = true; + } + m_ready = true; } diff --git a/src/crypto/CryptoNight.cpp b/src/crypto/CryptoNight.cpp index a96ac7611..b6273dc52 100644 --- a/src/crypto/CryptoNight.cpp +++ b/src/crypto/CryptoNight.cpp @@ -24,56 +24,93 @@ #include "crypto/CryptoNight.h" #include "crypto/CryptoNight_p.h" +#include "crypto/CryptoNight_test.h" #include "Options.h" -const static uint8_t test_input[152] = { - 0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19, - 0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9, - 0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F, - 0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46, - 0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02, - 0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00, - 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B, - 0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62, - 0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92, - 0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01 -}; - - -const static uint8_t test_output0[64] = { - 0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66, - 0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F, - 0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7, - 0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00 -}; - - -#ifndef XMRIG_NO_AEON -const static uint8_t test_output1[64] = { - 0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE, - 0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD, - 0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E, - 0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88, -}; - -//void cryptonight_lite_av1_aesni(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -//void cryptonight_lite_av2_aesni_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -//void cryptonight_lite_av3_softaes(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -//void cryptonight_lite_av4_softaes_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -#endif - - -static inline void cryptonight_av1_aesni(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { - cryptonight_hash<0x80000, MEMORY, 0x1FFFF0, false>(input, size, output, ctx); -} - - void (*cryptonight_hash_ctx)(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = nullptr; -static bool self_test(int algo) { - if (cryptonight_hash_ctx == NULL) { +static void cryptonight_av1_aesni(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_hash<0x80000, MEMORY, 0x1FFFF0, false>(input, size, output, ctx); +} + + +static void cryptonight_av2_aesni_double(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_double_hash<0x80000, MEMORY, 0x1FFFF0, false>(input, size, output, ctx); +} + + +static void cryptonight_av3_softaes(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_hash<0x80000, MEMORY, 0x1FFFF0, true>(input, size, output, ctx); +} + + +static void cryptonight_av4_softaes_double(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_double_hash<0x80000, MEMORY, 0x1FFFF0, true>(input, size, output, ctx); +} + + +#ifndef XMRIG_NO_AEON +static void cryptonight_lite_av1_aesni(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_hash<0x40000, MEMORY_LITE, 0xFFFF0, false>(input, size, output, ctx); +} + + +static void cryptonight_lite_av2_aesni_double(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_double_hash<0x40000, MEMORY_LITE, 0xFFFF0, false>(input, size, output, ctx); +} + + +static void cryptonight_lite_av3_softaes(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_hash<0x40000, MEMORY_LITE, 0xFFFF0, true>(input, size, output, ctx); +} + + +static void cryptonight_lite_av4_softaes_double(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) { + cryptonight_double_hash<0x40000, MEMORY_LITE, 0xFFFF0, true>(input, size, output, ctx); +} + +void (*cryptonight_variations[8])(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = { + cryptonight_av1_aesni, + cryptonight_av2_aesni_double, + cryptonight_av3_softaes, + cryptonight_av4_softaes_double, + cryptonight_lite_av1_aesni, + cryptonight_lite_av2_aesni_double, + cryptonight_lite_av3_softaes, + cryptonight_lite_av4_softaes_double + }; +#else +void (*cryptonight_variations[4])(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = { + cryptonight_av1_aesni, + cryptonight_av2_aesni_double, + cryptonight_av3_softaes, + cryptonight_av4_softaes_double + }; +#endif + + +bool CryptoNight::init(int algo, int variant) +{ + if (variant < 1 || variant > 4) { + return false; + } + +# ifndef XMRIG_NO_AEON + const int index = algo == Options::ALGO_CRYPTONIGHT_LITE ? (variant + 3) : (variant - 1); +# else + const int index = variant - 1; +# endif + + cryptonight_hash_ctx = cryptonight_variations[index]; + + return selfTest(algo); +} + + +bool CryptoNight::selfTest(int algo) { + if (cryptonight_hash_ctx == nullptr) { return false; } @@ -87,19 +124,5 @@ static bool self_test(int algo) { _mm_free(ctx->memory); _mm_free(ctx); -# ifndef XMRIG_NO_AEON - if (algo == Options::ALGO_CRYPTONIGHT_LITE) { - return memcmp(output, test_output1, (Options::i()->doubleHash() ? 64 : 32)) == 0; - } -# endif - - return memcmp(output, test_output0, (Options::i()->doubleHash() ? 64 : 32)) == 0; -} - - -bool CryptoNight::init(int algo, int variant) -{ - cryptonight_hash_ctx = cryptonight_av1_aesni; - - return self_test(algo); + return memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, (Options::i()->doubleHash() ? 64 : 32)) == 0; } diff --git a/src/crypto/CryptoNight.h b/src/crypto/CryptoNight.h index 1c201af38..ce1b7ba83 100644 --- a/src/crypto/CryptoNight.h +++ b/src/crypto/CryptoNight.h @@ -24,11 +24,14 @@ #ifndef __CRYPTONIGHT_H__ #define __CRYPTONIGHT_H__ + #include + #define MEMORY 2097152 /* 2 MiB */ #define MEMORY_LITE 1048576 /* 1 MiB */ + struct cryptonight_ctx { uint8_t state0[200] __attribute__((aligned(16))); uint8_t state1[200] __attribute__((aligned(16))); @@ -40,6 +43,9 @@ class CryptoNight { public: static bool init(int algo, int variant); + +private: + static bool selfTest(int algo); }; #endif /* __CRYPTONIGHT_H__ */ diff --git a/src/crypto/CryptoNight_p.h b/src/crypto/CryptoNight_p.h index 28ca790d3..ed24a510b 100644 --- a/src/crypto/CryptoNight_p.h +++ b/src/crypto/CryptoNight_p.h @@ -38,6 +38,9 @@ extern "C" #include "crypto/c_blake256.h" #include "crypto/c_jh.h" #include "crypto/c_skein.h" + +__m128i soft_aesenc(__m128i in, __m128i key); +__m128i soft_aeskeygenassist(__m128i key, uint8_t rcon); } @@ -64,14 +67,11 @@ static inline void do_skein_hash(const void* input, size_t len, char* output) { void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash}; -__m128i soft_aesenc(__m128i in, __m128i key); -__m128i soft_aeskeygenassist(__m128i key, uint8_t rcon); - #if defined(__x86_64__) # define EXTRACT64(X) _mm_cvtsi128_si64(X) -static inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi) +static inline uint64_t __umul128(uint64_t a, uint64_t b, uint64_t* hi) { unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b; *hi = r >> 64; @@ -86,7 +86,7 @@ static inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi) ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32)) -static inline uint64_t _umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) { +static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) { // multiplier = ab = a * 2^32 + b // multiplicand = cd = c * 2^32 + d // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d @@ -300,7 +300,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) template -void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx) +inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx) { keccak(static_cast(input), size, ctx->state0, 200); @@ -327,7 +327,7 @@ void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restr uint64_t hi, lo, cl, ch; cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - lo = _umul128(idx0, cl, &hi); + lo = __umul128(idx0, cl, &hi); al0 += hi; ah0 += lo; @@ -346,4 +346,86 @@ void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restr extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, static_cast(output)); } + +template +inline void cryptonight_double_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx) +{ + keccak((const uint8_t *) input, size, ctx->state0, 200); + keccak((const uint8_t *) input + size, size, ctx->state1, 200); + + const uint8_t* l0 = ctx->memory; + const uint8_t* l1 = ctx->memory + MEMORY; + uint64_t* h0 = reinterpret_cast(ctx->state0); + uint64_t* h1 = reinterpret_cast(ctx->state1); + + cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); + cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + + uint64_t al0 = h0[0] ^ h0[4]; + uint64_t al1 = h1[0] ^ h1[4]; + uint64_t ah0 = h0[1] ^ h0[5]; + uint64_t ah1 = h1[1] ^ h1[5]; + + __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]); + + uint64_t idx0 = h0[0] ^ h0[4]; + uint64_t idx1 = h1[0] ^ h1[4]; + + for (size_t i = 0; __builtin_expect(i < ITERATIONS, 1); i++) { + __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); + __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); + + cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0)); + cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1)); + + _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); + _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); + + idx0 = EXTRACT64(cx0); + idx1 = EXTRACT64(cx1); + + bx0 = cx0; + bx1 = cx1; + + uint64_t hi, lo, cl, ch; + cl = ((uint64_t*) &l0[idx0 & MASK])[0]; + ch = ((uint64_t*) &l0[idx0 & MASK])[1]; + lo = __umul128(idx0, cl, &hi); + + al0 += hi; + ah0 += lo; + + ((uint64_t*) &l0[idx0 & MASK])[0] = al0; + ((uint64_t*) &l0[idx0 & MASK])[1] = ah0; + + ah0 ^= ch; + al0 ^= cl; + idx0 = al0; + + cl = ((uint64_t*) &l1[idx1 & MASK])[0]; + ch = ((uint64_t*) &l1[idx1 & MASK])[1]; + lo = __umul128(idx1, cl, &hi); + + al1 += hi; + ah1 += lo; + + ((uint64_t*) &l1[idx1 & MASK])[0] = al1; + ((uint64_t*) &l1[idx1 & MASK])[1] = ah1; + + ah1 ^= ch; + al1 ^= cl; + idx1 = al1; + } + + cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); + cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + + keccakf(h0, 24); + keccakf(h1, 24); + + extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, static_cast(output)); + extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, static_cast(output) + 32); +} + #endif /* __CRYPTONIGHT_P_H__ */ diff --git a/src/crypto/CryptoNight_test.h b/src/crypto/CryptoNight_test.h new file mode 100644 index 000000000..b2985379b --- /dev/null +++ b/src/crypto/CryptoNight_test.h @@ -0,0 +1,60 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CRYPTONIGHT_TEST_H__ +#define __CRYPTONIGHT_TEST_H__ + + +const static uint8_t test_input[152] = { + 0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19, + 0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9, + 0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F, + 0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46, + 0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02, + 0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00, + 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B, + 0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62, + 0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92, + 0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01 +}; + + +const static uint8_t test_output0[64] = { + 0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66, + 0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F, + 0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7, + 0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00 +}; + + +#ifndef XMRIG_NO_AEON +const static uint8_t test_output1[64] = { + 0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE, + 0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD, + 0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E, + 0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88, +}; +#endif + + +#endif /* __CRYPTONIGHT_TEST_H__ */