dataset.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. Copyright (c) 2018 tevador
  3. This file is part of RandomX.
  4. RandomX is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. RandomX is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with RandomX. If not, see<http://www.gnu.org/licenses/>.
  14. */
  15. /* Original code from Argon2 reference source code package used under CC0 Licence
  16. * https://github.com/P-H-C/phc-winner-argon2
  17. * Copyright 2015
  18. * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
  19. */
  20. #include <new>
  21. #include <algorithm>
  22. #include <stdexcept>
  23. #include <cstring>
  24. #include <limits>
  25. #include <cstring>
  26. #include "common.hpp"
  27. #include "dataset.hpp"
  28. #include "virtual_memory.hpp"
  29. #include "superscalar.hpp"
  30. #include "blake2_generator.hpp"
  31. #include "reciprocal.h"
  32. #include "blake2/endian.h"
  33. #include "argon2.h"
  34. #include "argon2_core.h"
  35. randomx_dataset::~randomx_dataset() {
  36. }
  37. static_assert(RANDOMX_ARGON_MEMORY % (RANDOMX_ARGON_LANES * ARGON2_SYNC_POINTS) == 0, "RANDOMX_ARGON_MEMORY - invalid value");
  38. void randomx_cache::initialize(const void *seed, size_t seedSize) {
  39. uint32_t memory_blocks, segment_length;
  40. argon2_instance_t instance;
  41. argon2_context context;
  42. context.out = nullptr;
  43. context.outlen = 0;
  44. context.pwd = CONST_CAST(uint8_t *)seed;
  45. context.pwdlen = (uint32_t)seedSize;
  46. context.salt = CONST_CAST(uint8_t *)RANDOMX_ARGON_SALT;
  47. context.saltlen = (uint32_t)randomx::ArgonSaltSize;
  48. context.secret = NULL;
  49. context.secretlen = 0;
  50. context.ad = NULL;
  51. context.adlen = 0;
  52. context.t_cost = RANDOMX_ARGON_ITERATIONS;
  53. context.m_cost = RANDOMX_ARGON_MEMORY;
  54. context.lanes = RANDOMX_ARGON_LANES;
  55. context.threads = 1;
  56. context.allocate_cbk = NULL;
  57. context.free_cbk = NULL;
  58. context.flags = ARGON2_DEFAULT_FLAGS;
  59. context.version = ARGON2_VERSION_NUMBER;
  60. /* 2. Align memory size */
  61. /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
  62. memory_blocks = context.m_cost;
  63. segment_length = memory_blocks / (context.lanes * ARGON2_SYNC_POINTS);
  64. instance.version = context.version;
  65. instance.memory = NULL;
  66. instance.passes = context.t_cost;
  67. instance.memory_blocks = memory_blocks;
  68. instance.segment_length = segment_length;
  69. instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
  70. instance.lanes = context.lanes;
  71. instance.threads = context.threads;
  72. instance.type = Argon2_d;
  73. instance.memory = (block*)memory;
  74. if (instance.threads > instance.lanes) {
  75. instance.threads = instance.lanes;
  76. }
  77. /* 3. Initialization: Hashing inputs, allocating memory, filling first
  78. * blocks
  79. */
  80. argon_initialize(&instance, &context);
  81. fill_memory_blocks(&instance);
  82. reciprocalCache.clear();
  83. randomx::Blake2Generator gen(seed, seedSize);
  84. for (int i = 0; i < RANDOMX_CACHE_ACCESSES; ++i) {
  85. randomx::generateSuperscalar(programs[i], gen);
  86. for (unsigned j = 0; j < programs[i].getSize(); ++j) {
  87. auto& instr = programs[i](j);
  88. if (instr.opcode == randomx::SuperscalarInstructionType::IMUL_RCP) {
  89. auto rcp = randomx_reciprocal(instr.getImm32());
  90. instr.setImm32(reciprocalCache.size());
  91. reciprocalCache.push_back(rcp);
  92. }
  93. }
  94. }
  95. }
  96. namespace randomx {
  97. template<class Allocator>
  98. void Dataset<Allocator>::allocate() {
  99. memory = (uint8_t*)Allocator::allocMemory(RANDOMX_DATASET_SIZE);
  100. }
  101. template<class Allocator>
  102. Dataset<Allocator>::~Dataset() {
  103. Allocator::freeMemory(memory, RANDOMX_DATASET_SIZE);
  104. }
  105. template<class Allocator>
  106. void Cache<Allocator>::allocate() {
  107. memory = (uint8_t*)Allocator::allocMemory(RANDOMX_ARGON_MEMORY * ARGON2_BLOCK_SIZE);
  108. }
  109. template<class Allocator>
  110. Cache<Allocator>::~Cache() {
  111. Allocator::freeMemory(memory, RANDOMX_ARGON_MEMORY * ARGON2_BLOCK_SIZE);
  112. }
  113. template<class Allocator>
  114. DatasetInitFunc Cache<Allocator>::getInitFunc() {
  115. return &initDataset;
  116. }
  117. template<class Allocator>
  118. DatasetInitFunc CacheWithJit<Allocator>::getInitFunc() {
  119. return jit.getDatasetInitFunc();
  120. }
  121. template<class Allocator>
  122. void CacheWithJit<Allocator>::initialize(const void *seed, size_t seedSize) {
  123. randomx_cache::initialize(seed, seedSize);
  124. jit.generateSuperscalarHash(programs, reciprocalCache);
  125. jit.generateDatasetInitCode();
  126. }
  127. template class Dataset<AlignedAllocator<CacheLineSize>>;
  128. template class Dataset<LargePageAllocator>;
  129. template class Cache<AlignedAllocator<CacheLineSize>>;
  130. template class Cache<LargePageAllocator>;
  131. template class CacheWithJit<AlignedAllocator<CacheLineSize>>;
  132. template class CacheWithJit<LargePageAllocator>;
  133. constexpr uint64_t superscalarMul0 = 6364136223846793005ULL;
  134. constexpr uint64_t superscalarAdd1 = 9298410992540426748ULL;
  135. constexpr uint64_t superscalarAdd2 = 12065312585734608966ULL;
  136. constexpr uint64_t superscalarAdd3 = 9306329213124610396ULL;
  137. constexpr uint64_t superscalarAdd4 = 5281919268842080866ULL;
  138. constexpr uint64_t superscalarAdd5 = 10536153434571861004ULL;
  139. constexpr uint64_t superscalarAdd6 = 3398623926847679864ULL;
  140. constexpr uint64_t superscalarAdd7 = 9549104520008361294ULL;
  141. static inline uint8_t* getMixBlock(uint64_t registerValue, uint8_t *memory) {
  142. constexpr uint32_t mask = (RANDOMX_ARGON_MEMORY * ArgonBlockSize / CacheLineSize - 1);
  143. return memory + (registerValue & mask) * CacheLineSize;
  144. }
  145. void initDatasetItem(randomx_cache* cache, uint8_t* out, uint64_t itemNumber) {
  146. int_reg_t rl[8];
  147. uint8_t* mixBlock;
  148. uint64_t registerValue = itemNumber;
  149. rl[0] = (itemNumber + 1) * superscalarMul0;
  150. rl[1] = rl[0] ^ superscalarAdd1;
  151. rl[2] = rl[0] ^ superscalarAdd2;
  152. rl[3] = rl[0] ^ superscalarAdd3;
  153. rl[4] = rl[0] ^ superscalarAdd4;
  154. rl[5] = rl[0] ^ superscalarAdd5;
  155. rl[6] = rl[0] ^ superscalarAdd6;
  156. rl[7] = rl[0] ^ superscalarAdd7;
  157. for (unsigned i = 0; i < RANDOMX_CACHE_ACCESSES; ++i) {
  158. mixBlock = getMixBlock(registerValue, cache->memory);
  159. SuperscalarProgram& prog = cache->programs[i];
  160. executeSuperscalar(rl, prog, &cache->reciprocalCache);
  161. for (unsigned q = 0; q < 8; ++q)
  162. rl[q] ^= load64(mixBlock + 8 * q);
  163. registerValue = rl[prog.getAddressRegister()];
  164. }
  165. memcpy(out, &rl, CacheLineSize);
  166. }
  167. void initDataset(randomx_cache* cache, uint8_t* dataset, uint32_t startItem, uint32_t endItem) {
  168. for (uint32_t itemNumber = startItem; itemNumber < endItem; ++itemNumber, dataset += CacheLineSize)
  169. initDatasetItem(cache, dataset, itemNumber);
  170. }
  171. }