dataset.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. #include "jit_compiler.hpp"
  36. #include "intrin_portable.h"
  37. static_assert(RANDOMX_ARGON_MEMORY % (RANDOMX_ARGON_LANES * ARGON2_SYNC_POINTS) == 0, "RANDOMX_ARGON_MEMORY - invalid value");
  38. static_assert(ARGON2_BLOCK_SIZE == randomx::ArgonBlockSize, "Unpexpected value of ARGON2_BLOCK_SIZE");
  39. namespace randomx {
  40. void initCache(randomx_cache* cache, const void* key, size_t keySize) {
  41. uint32_t memory_blocks, segment_length;
  42. argon2_instance_t instance;
  43. argon2_context context;
  44. context.out = nullptr;
  45. context.outlen = 0;
  46. context.pwd = CONST_CAST(uint8_t *)key;
  47. context.pwdlen = (uint32_t)keySize;
  48. context.salt = CONST_CAST(uint8_t *)RANDOMX_ARGON_SALT;
  49. context.saltlen = (uint32_t)randomx::ArgonSaltSize;
  50. context.secret = NULL;
  51. context.secretlen = 0;
  52. context.ad = NULL;
  53. context.adlen = 0;
  54. context.t_cost = RANDOMX_ARGON_ITERATIONS;
  55. context.m_cost = RANDOMX_ARGON_MEMORY;
  56. context.lanes = RANDOMX_ARGON_LANES;
  57. context.threads = 1;
  58. context.allocate_cbk = NULL;
  59. context.free_cbk = NULL;
  60. context.flags = ARGON2_DEFAULT_FLAGS;
  61. context.version = ARGON2_VERSION_NUMBER;
  62. /* 2. Align memory size */
  63. /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
  64. memory_blocks = context.m_cost;
  65. segment_length = memory_blocks / (context.lanes * ARGON2_SYNC_POINTS);
  66. instance.version = context.version;
  67. instance.memory = NULL;
  68. instance.passes = context.t_cost;
  69. instance.memory_blocks = memory_blocks;
  70. instance.segment_length = segment_length;
  71. instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
  72. instance.lanes = context.lanes;
  73. instance.threads = context.threads;
  74. instance.type = Argon2_d;
  75. instance.memory = (block*)cache->memory;
  76. if (instance.threads > instance.lanes) {
  77. instance.threads = instance.lanes;
  78. }
  79. /* 3. Initialization: Hashing inputs, allocating memory, filling first
  80. * blocks
  81. */
  82. argon_initialize(&instance, &context);
  83. fill_memory_blocks(&instance);
  84. cache->reciprocalCache.clear();
  85. randomx::Blake2Generator gen(key, keySize);
  86. for (int i = 0; i < RANDOMX_CACHE_ACCESSES; ++i) {
  87. randomx::generateSuperscalar(cache->programs[i], gen);
  88. for (unsigned j = 0; j < cache->programs[i].getSize(); ++j) {
  89. auto& instr = cache->programs[i](j);
  90. if (instr.opcode == randomx::SuperscalarInstructionType::IMUL_RCP) {
  91. auto rcp = randomx_reciprocal(instr.getImm32());
  92. instr.setImm32(cache->reciprocalCache.size());
  93. cache->reciprocalCache.push_back(rcp);
  94. }
  95. }
  96. }
  97. }
  98. void initCacheCompile(randomx_cache* cache, const void* key, size_t keySize) {
  99. initCache(cache, key, keySize);
  100. cache->jit->generateSuperscalarHash(cache->programs, cache->reciprocalCache);
  101. cache->jit->generateDatasetInitCode();
  102. }
  103. constexpr uint64_t superscalarMul0 = 6364136223846793005ULL;
  104. constexpr uint64_t superscalarAdd1 = 9298411001130361340ULL;
  105. constexpr uint64_t superscalarAdd2 = 12065312585734608966ULL;
  106. constexpr uint64_t superscalarAdd3 = 9306329213124626780ULL;
  107. constexpr uint64_t superscalarAdd4 = 5281919268842080866ULL;
  108. constexpr uint64_t superscalarAdd5 = 10536153434571861004ULL;
  109. constexpr uint64_t superscalarAdd6 = 3398623926847679864ULL;
  110. constexpr uint64_t superscalarAdd7 = 9549104520008361294ULL;
  111. static inline uint8_t* getMixBlock(uint64_t registerValue, uint8_t *memory) {
  112. constexpr uint32_t mask = CacheSize / CacheLineSize - 1;
  113. return memory + (registerValue & mask) * CacheLineSize;
  114. }
  115. void initDatasetItem(randomx_cache* cache, uint8_t* out, uint64_t itemNumber) {
  116. int_reg_t rl[8];
  117. uint8_t* mixBlock;
  118. uint64_t registerValue = itemNumber;
  119. rl[0] = (itemNumber + 1) * superscalarMul0;
  120. rl[1] = rl[0] ^ superscalarAdd1;
  121. rl[2] = rl[0] ^ superscalarAdd2;
  122. rl[3] = rl[0] ^ superscalarAdd3;
  123. rl[4] = rl[0] ^ superscalarAdd4;
  124. rl[5] = rl[0] ^ superscalarAdd5;
  125. rl[6] = rl[0] ^ superscalarAdd6;
  126. rl[7] = rl[0] ^ superscalarAdd7;
  127. for (unsigned i = 0; i < RANDOMX_CACHE_ACCESSES; ++i) {
  128. mixBlock = getMixBlock(registerValue, cache->memory);
  129. PREFETCHNTA(mixBlock);
  130. SuperscalarProgram& prog = cache->programs[i];
  131. executeSuperscalar(rl, prog, &cache->reciprocalCache);
  132. for (unsigned q = 0; q < 8; ++q)
  133. rl[q] ^= load64_native(mixBlock + 8 * q);
  134. registerValue = rl[prog.getAddressRegister()];
  135. }
  136. memcpy(out, &rl, CacheLineSize);
  137. }
  138. void initDataset(randomx_cache* cache, uint8_t* dataset, uint32_t startItem, uint32_t endItem) {
  139. for (uint32_t itemNumber = startItem; itemNumber < endItem; ++itemNumber, dataset += CacheLineSize)
  140. initDatasetItem(cache, dataset, itemNumber);
  141. }
  142. }