|
|
@@ -19,135 +19,25 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
|
|
|
|
|
// Parts of this file are originally copyright (c) xmr-stak
|
|
|
|
|
|
-#include "common.hpp"
|
|
|
-#include "dataset.hpp"
|
|
|
-#include "Pcg32.hpp"
|
|
|
-#include "argon2_core.h"
|
|
|
#include <new>
|
|
|
#include <algorithm>
|
|
|
#include <stdexcept>
|
|
|
#include <cstring>
|
|
|
|
|
|
-#if defined(_MSC_VER)
|
|
|
-#if defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP == 2)
|
|
|
-#define __SSE2__ 1
|
|
|
-#endif
|
|
|
-#endif
|
|
|
+#include "common.hpp"
|
|
|
+#include "dataset.hpp"
|
|
|
+#include "Pcg32.hpp"
|
|
|
+#include "Cache.hpp"
|
|
|
|
|
|
#if defined(__SSE2__)
|
|
|
#include <wmmintrin.h>
|
|
|
-#define PREFETCH(memory) _mm_prefetch((const char *)((memory).dataset + (memory).ma), _MM_HINT_T0)
|
|
|
+#define PREFETCH(memory) _mm_prefetch((const char *)((memory).ds.dataset + (memory).ma), _MM_HINT_T0)
|
|
|
#else
|
|
|
#define PREFETCH(memory)
|
|
|
#endif
|
|
|
|
|
|
namespace RandomX {
|
|
|
|
|
|
- void initializeCache(const void* input, size_t inputLength, void* memory) {
|
|
|
- uint32_t memory_blocks, segment_length;
|
|
|
- argon2_instance_t instance;
|
|
|
- argon2_context context;
|
|
|
-
|
|
|
- context.out = nullptr;
|
|
|
- context.outlen = 0;
|
|
|
- context.pwd = CONST_CAST(uint8_t *)input;
|
|
|
- context.pwdlen = (uint32_t)inputLength;
|
|
|
- context.salt = CONST_CAST(uint8_t *)ArgonSalt;
|
|
|
- context.saltlen = (uint32_t)ArgonSaltSize;
|
|
|
- context.secret = NULL;
|
|
|
- context.secretlen = 0;
|
|
|
- context.ad = NULL;
|
|
|
- context.adlen = 0;
|
|
|
- context.t_cost = ArgonIterations;
|
|
|
- context.m_cost = ArgonMemorySize;
|
|
|
- context.lanes = ArgonLanes;
|
|
|
- context.threads = 1;
|
|
|
- context.allocate_cbk = NULL;
|
|
|
- context.free_cbk = NULL;
|
|
|
- context.flags = ARGON2_DEFAULT_FLAGS;
|
|
|
- context.version = ARGON2_VERSION_NUMBER;
|
|
|
-
|
|
|
- /* 2. Align memory size */
|
|
|
- /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
|
|
|
- memory_blocks = context.m_cost;
|
|
|
-
|
|
|
- segment_length = memory_blocks / (context.lanes * ARGON2_SYNC_POINTS);
|
|
|
-
|
|
|
- instance.version = context.version;
|
|
|
- instance.memory = NULL;
|
|
|
- instance.passes = context.t_cost;
|
|
|
- instance.memory_blocks = memory_blocks;
|
|
|
- instance.segment_length = segment_length;
|
|
|
- instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
|
|
|
- instance.lanes = context.lanes;
|
|
|
- instance.threads = context.threads;
|
|
|
- instance.type = Argon2_d;
|
|
|
- instance.memory = (block*)memory;
|
|
|
-
|
|
|
- if (instance.threads > instance.lanes) {
|
|
|
- instance.threads = instance.lanes;
|
|
|
- }
|
|
|
-
|
|
|
- /* 3. Initialization: Hashing inputs, allocating memory, filling first
|
|
|
- * blocks
|
|
|
- */
|
|
|
- initialize(&instance, &context);
|
|
|
-
|
|
|
- fill_memory_blocks(&instance);
|
|
|
- }
|
|
|
-
|
|
|
- // This will shift and xor tmp1 into itself as 4 32-bit vals such as
|
|
|
- // sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
|
|
|
- static inline __m128i sl_xor(__m128i tmp1) {
|
|
|
- __m128i tmp4;
|
|
|
- tmp4 = _mm_slli_si128(tmp1, 0x04);
|
|
|
- tmp1 = _mm_xor_si128(tmp1, tmp4);
|
|
|
- tmp4 = _mm_slli_si128(tmp4, 0x04);
|
|
|
- tmp1 = _mm_xor_si128(tmp1, tmp4);
|
|
|
- tmp4 = _mm_slli_si128(tmp4, 0x04);
|
|
|
- tmp1 = _mm_xor_si128(tmp1, tmp4);
|
|
|
- return tmp1;
|
|
|
- }
|
|
|
-
|
|
|
- template<uint8_t rcon, bool soft>
|
|
|
- static inline void aes_genkey_sub(__m128i* xout0, __m128i* xout2) {
|
|
|
- __m128i xout1 = soft ? soft_aeskeygenassist(*xout2, rcon) : _mm_aeskeygenassist_si128(*xout2, rcon);
|
|
|
- xout1 = _mm_shuffle_epi32(xout1, 0xFF);
|
|
|
- *xout0 = sl_xor(*xout0);
|
|
|
- *xout0 = _mm_xor_si128(*xout0, xout1);
|
|
|
- xout1 = soft ? soft_aeskeygenassist(*xout0, 0x00) : _mm_aeskeygenassist_si128(*xout0, 0x00);
|
|
|
- xout1 = _mm_shuffle_epi32(xout1, 0xAA);
|
|
|
- *xout2 = sl_xor(*xout2);
|
|
|
- *xout2 = _mm_xor_si128(*xout2, xout1);
|
|
|
- }
|
|
|
-
|
|
|
- template<bool soft>
|
|
|
- void expandAesKeys(const __m128i* seed, __m128i* keys) {
|
|
|
- __m128i xout0, xout2;
|
|
|
- xout0 = _mm_load_si128(seed);
|
|
|
- xout2 = _mm_load_si128(seed + 1);
|
|
|
- *keys++ = xout0;
|
|
|
- *keys++ = xout2;
|
|
|
- aes_genkey_sub<0x01, soft>(&xout0, &xout2);
|
|
|
- *keys++ = xout0;
|
|
|
- *keys++ = xout2;
|
|
|
- aes_genkey_sub<0x02, soft>(&xout0, &xout2);
|
|
|
- *keys++ = xout0;
|
|
|
- *keys++ = xout2;
|
|
|
- aes_genkey_sub<0x04, soft>(&xout0, &xout2);
|
|
|
- *keys++ = xout0;
|
|
|
- *keys++ = xout2;
|
|
|
- aes_genkey_sub<0x08, soft>(&xout0, &xout2);
|
|
|
- *keys++ = xout0;
|
|
|
- *keys++ = xout2;
|
|
|
- }
|
|
|
-
|
|
|
- template
|
|
|
- void expandAesKeys<true>(const __m128i* seed, __m128i* keys);
|
|
|
-
|
|
|
- template
|
|
|
- void expandAesKeys<false>(const __m128i* seed, __m128i* keys);
|
|
|
-
|
|
|
template<typename T>
|
|
|
static inline void shuffle(T* buffer, size_t bytes, Pcg32& gen) {
|
|
|
auto count = bytes / sizeof(T);
|
|
|
@@ -157,8 +47,18 @@ namespace RandomX {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ template<bool soft>
|
|
|
+ static inline __m128i aesenc(__m128i in, __m128i key) {
|
|
|
+ return soft ? soft_aesenc(in, key) : _mm_aesenc_si128(in, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ template<bool soft>
|
|
|
+ static inline __m128i aesdec(__m128i in, __m128i key) {
|
|
|
+ return soft ? soft_aesdec(in, key) : _mm_aesdec_si128(in, key);
|
|
|
+ }
|
|
|
+
|
|
|
template<bool soft, bool enc>
|
|
|
- void initBlock(uint8_t* in, uint8_t* out, uint32_t blockNumber, const __m128i keys[10]) {
|
|
|
+ void initBlock(const uint8_t* in, uint8_t* out, uint32_t blockNumber, const KeysContainer& keys) {
|
|
|
__m128i xin, xout;
|
|
|
//Initialization vector = block number extended to 128 bits
|
|
|
xout = _mm_cvtsi32_si128(blockNumber);
|
|
|
@@ -200,20 +100,20 @@ namespace RandomX {
|
|
|
}
|
|
|
|
|
|
template
|
|
|
- void initBlock<true, true>(uint8_t* in, uint8_t* out, uint32_t blockNumber, const __m128i keys[10]);
|
|
|
+ void initBlock<true, true>(const uint8_t*, uint8_t*, uint32_t, const KeysContainer&);
|
|
|
|
|
|
template
|
|
|
- void initBlock<true, false>(uint8_t* in, uint8_t* out, uint32_t blockNumber, const __m128i keys[10]);
|
|
|
+ void initBlock<true, false>(const uint8_t*, uint8_t*, uint32_t, const KeysContainer&);
|
|
|
|
|
|
template
|
|
|
- void initBlock<false, true>(uint8_t* in, uint8_t* out, uint32_t blockNumber, const __m128i keys[10]);
|
|
|
+ void initBlock<false, true>(const uint8_t*, uint8_t*, uint32_t, const KeysContainer&);
|
|
|
|
|
|
template
|
|
|
- void initBlock<false, false>(uint8_t* in, uint8_t* out, uint32_t blockNumber, const __m128i keys[10]);
|
|
|
+ void initBlock<false, false>(const uint8_t*, uint8_t*, uint32_t, const KeysContainer&);
|
|
|
|
|
|
convertible_t datasetRead(addr_t addr, MemoryRegisters& memory) {
|
|
|
convertible_t data;
|
|
|
- data.u64 = *(uint64_t*)(memory.dataset + memory.ma);
|
|
|
+ data.u64 = *(uint64_t*)(memory.ds.dataset + memory.ma);
|
|
|
memory.ma += 8;
|
|
|
memory.mx ^= addr;
|
|
|
if ((memory.mx & 0xFFF8) == 0) {
|
|
|
@@ -224,24 +124,25 @@ namespace RandomX {
|
|
|
}
|
|
|
|
|
|
template<bool softAes>
|
|
|
- void initBlock(uint8_t* cache, uint8_t* block, uint32_t blockNumber, const __m128i k[10]) {
|
|
|
+ void initBlock(const uint8_t* cache, uint8_t* block, uint32_t blockNumber, const KeysContainer& keys) {
|
|
|
if (blockNumber % 2 == 1) {
|
|
|
- initBlock<softAes, true>(cache + blockNumber * CacheBlockSize, block, blockNumber, k);
|
|
|
+ initBlock<softAes, true>(cache + blockNumber * CacheBlockSize, block, blockNumber, keys);
|
|
|
}
|
|
|
else {
|
|
|
- initBlock<softAes, false>(cache + blockNumber * CacheBlockSize, block, blockNumber, k);
|
|
|
+ initBlock<softAes, false>(cache + blockNumber * CacheBlockSize, block, blockNumber, keys);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
template<bool softAes>
|
|
|
convertible_t datasetReadLight(addr_t addr, MemoryRegisters& memory) {
|
|
|
convertible_t data;
|
|
|
+ LightClientDataset* lds = memory.ds.lightDataset;
|
|
|
auto blockNumber = memory.ma / DatasetBlockSize;
|
|
|
- if (memory.lcm->blockNumber != blockNumber) {
|
|
|
- initBlock<softAes>(memory.lcm->cache + CacheShift, (uint8_t*)memory.lcm->block, blockNumber, memory.lcm->keys);
|
|
|
- memory.lcm->blockNumber = blockNumber;
|
|
|
+ if (lds->blockNumber != blockNumber) {
|
|
|
+ initBlock<softAes>(lds->cache->getCache(), (uint8_t*)lds->block, blockNumber, lds->cache->getKeys());
|
|
|
+ lds->blockNumber = blockNumber;
|
|
|
}
|
|
|
- data.u64 = *(uint64_t*)(memory.lcm->block + (memory.ma % DatasetBlockSize));
|
|
|
+ data.u64 = *(uint64_t*)(lds->block + (memory.ma % DatasetBlockSize));
|
|
|
memory.ma += 8;
|
|
|
memory.mx ^= addr;
|
|
|
if ((memory.mx & 0xFFF8) == 0) {
|
|
|
@@ -256,54 +157,37 @@ namespace RandomX {
|
|
|
template
|
|
|
convertible_t datasetReadLight<true>(addr_t addr, MemoryRegisters& memory);
|
|
|
|
|
|
- template<bool softAes>
|
|
|
- void datasetInit(const void* seed, uint8_t*& dataset) {
|
|
|
+ void datasetAlloc(dataset_t& ds) {
|
|
|
if (sizeof(size_t) <= 4)
|
|
|
throw std::runtime_error("Platform doesn't support enough memory for the dataset");
|
|
|
- dataset = (uint8_t*)_mm_malloc(DatasetSize, sizeof(__m128i));
|
|
|
- if (dataset == nullptr) {
|
|
|
- throw std::runtime_error("Dataset memory allocation failed. >4 GiB of virtual memory is needed.");
|
|
|
- }
|
|
|
- uint8_t* cache = (uint8_t*)_mm_malloc(CacheSize + CacheShift, sizeof(__m128i));
|
|
|
- if (cache == nullptr) {
|
|
|
- throw std::bad_alloc();
|
|
|
+ ds.dataset = (uint8_t*)_mm_malloc(DatasetSize, /*sizeof(__m128i)*/ 64);
|
|
|
+ if (ds.dataset == nullptr) {
|
|
|
+ throw std::runtime_error("Dataset memory allocation failed. >4 GiB of free virtual memory is needed.");
|
|
|
}
|
|
|
- initializeCache(seed, SeedSize, cache);
|
|
|
- memcpy(cache + CacheSize, cache, CacheShift);
|
|
|
- alignas(16) __m128i keys[10];
|
|
|
- expandAesKeys<softAes>((const __m128i*)seed, keys);
|
|
|
- for (uint32_t i = 0; i < DatasetBlockCount; ++i) {
|
|
|
- initBlock<softAes>(cache + CacheShift, dataset + i * DatasetBlockSize, i, keys);
|
|
|
+ }
|
|
|
+
|
|
|
+ template<bool softAes>
|
|
|
+ void datasetInit(Cache* cache, dataset_t ds, uint32_t startBlock, uint32_t blockCount) {
|
|
|
+ for (uint32_t i = startBlock; i < startBlock + blockCount; ++i) {
|
|
|
+ initBlock<softAes>(cache->getCache(), ds.dataset + i * DatasetBlockSize, i, cache->getKeys());
|
|
|
}
|
|
|
- _mm_free(cache);
|
|
|
}
|
|
|
|
|
|
template
|
|
|
- void datasetInit<false>(const void*, uint8_t*&);
|
|
|
+ void datasetInit<false>(Cache*, dataset_t, uint32_t, uint32_t);
|
|
|
|
|
|
template
|
|
|
- void datasetInit<true>(const void*, uint8_t*&);
|
|
|
+ void datasetInit<true>(Cache*, dataset_t, uint32_t, uint32_t);
|
|
|
|
|
|
template<bool softAes>
|
|
|
- void datasetInitLight(const void* seed, LightClientMemory*& lcm) {
|
|
|
- lcm = new LightClientMemory();
|
|
|
- lcm->cache = (uint8_t*)_mm_malloc(CacheSize + CacheShift, sizeof(__m128i));
|
|
|
- if (lcm->cache == nullptr) {
|
|
|
- throw std::bad_alloc();
|
|
|
- }
|
|
|
- initializeCache(seed, SeedSize, lcm->cache);
|
|
|
- memcpy(lcm->cache + CacheSize, lcm->cache, CacheShift);
|
|
|
- expandAesKeys<softAes>((__m128i*)seed, lcm->keys);
|
|
|
- lcm->block = (uint8_t*)_mm_malloc(DatasetBlockSize, sizeof(__m128i));
|
|
|
- if (lcm->block == nullptr) {
|
|
|
- throw std::bad_alloc();
|
|
|
- }
|
|
|
- lcm->blockNumber = -1;
|
|
|
+ void datasetInitCache(const void* seed, dataset_t& ds) {
|
|
|
+ ds.cache = new Cache();
|
|
|
+ ds.cache->initialize<softAes>(seed, SeedSize);
|
|
|
}
|
|
|
|
|
|
template
|
|
|
- void datasetInitLight<false>(const void*, LightClientMemory*&);
|
|
|
+ void datasetInitCache<false>(const void*, dataset_t&);
|
|
|
|
|
|
template
|
|
|
- void datasetInitLight<true>(const void*, LightClientMemory*&);
|
|
|
+ void datasetInitCache<true>(const void*, dataset_t&);
|
|
|
}
|