entropy.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #include "fast.h"
  2. #include "random.h"
  3. #include "entropy.h"
  4. #include "mersenne.h"
  5. #include "shuffle.h"
  6. #include "init_atfork.h"
  7. #include <util/stream/output.h>
  8. #include <util/stream/mem.h>
  9. #include <util/stream/zlib.h>
  10. #include <util/stream/buffer.h>
  11. #include <util/system/fs.h>
  12. #include <util/system/info.h>
  13. #include <util/system/spinlock.h>
  14. #include <util/system/thread.h>
  15. #include <util/system/execpath.h>
  16. #include <util/system/datetime.h>
  17. #include <util/system/hostname.h>
  18. #include <util/system/getpid.h>
  19. #include <util/system/mem_info.h>
  20. #include <util/system/rusage.h>
  21. #include <util/system/cpu_id.h>
  22. #include <util/system/unaligned_mem.h>
  23. #include <util/generic/buffer.h>
  24. #include <util/generic/singleton.h>
  25. #include <util/digest/murmur.h>
  26. #include <util/digest/city.h>
  27. #include <util/ysaveload.h>
  28. namespace {
  29. inline void Permute(char* buf, size_t len, ui32 seed) noexcept {
  30. Shuffle(buf, buf + len, TReallyFastRng32(seed));
  31. }
  32. struct THostEntropy: public TBuffer {
  33. inline THostEntropy() {
  34. {
  35. TBufferOutput buf(*this);
  36. TZLibCompress out(&buf);
  37. Save(&out, GetPID());
  38. Save(&out, GetCycleCount());
  39. Save(&out, MicroSeconds());
  40. Save(&out, TThread::CurrentThreadId());
  41. Save(&out, NSystemInfo::CachedNumberOfCpus());
  42. Save(&out, NSystemInfo::TotalMemorySize());
  43. Save(&out, HostName());
  44. try {
  45. Save(&out, GetExecPath());
  46. } catch (...) {
  47. // workaround - sometimes fails on FreeBSD
  48. }
  49. Save(&out, (size_t)Data());
  50. Save(&out, (size_t)&buf);
  51. {
  52. double la[3];
  53. NSystemInfo::LoadAverage(la, Y_ARRAY_SIZE(la));
  54. out.Write(la, sizeof(la));
  55. }
  56. {
  57. auto mi = NMemInfo::GetMemInfo();
  58. out.Write(&mi, sizeof(mi));
  59. }
  60. {
  61. auto ru = TRusage::Get();
  62. out.Write(&ru, sizeof(ru));
  63. }
  64. {
  65. ui32 store[12];
  66. out << TStringBuf(CpuBrand(store));
  67. }
  68. out << NFs::CurrentWorkingDirectory();
  69. out.Finish();
  70. }
  71. {
  72. TMemoryOutput out(Data(), Size());
  73. // replace zlib header with hash
  74. Save(&out, CityHash64(Data(), Size()));
  75. }
  76. Permute(Data(), Size(), MurmurHash<ui32>(Data(), Size()));
  77. }
  78. };
  79. // not thread-safe
  80. class TMersenneInput: public IInputStream {
  81. using TKey = ui64;
  82. using TRnd = TMersenne<TKey>;
  83. public:
  84. inline explicit TMersenneInput(const TBuffer& rnd)
  85. : Rnd_((const TKey*)rnd.Data(), rnd.Size() / sizeof(TKey))
  86. {
  87. }
  88. ~TMersenneInput() override = default;
  89. size_t DoRead(void* buf, size_t len) override {
  90. size_t toRead = len;
  91. while (toRead) {
  92. const TKey next = Rnd_.GenRand();
  93. const size_t toCopy = Min(toRead, sizeof(next));
  94. memcpy(buf, &next, toCopy);
  95. buf = (char*)buf + toCopy;
  96. toRead -= toCopy;
  97. }
  98. return len;
  99. }
  100. private:
  101. TRnd Rnd_;
  102. };
  103. class TEntropyPoolStream: public IInputStream {
  104. public:
  105. inline explicit TEntropyPoolStream(const TBuffer& buffer)
  106. : Mi_(buffer)
  107. , Bi_(&Mi_, 8192)
  108. {
  109. }
  110. size_t DoRead(void* buf, size_t len) override {
  111. auto guard = Guard(Mutex_);
  112. return Bi_.Read(buf, len);
  113. }
  114. private:
  115. TAdaptiveLock Mutex_;
  116. TMersenneInput Mi_;
  117. TBufferedInput Bi_;
  118. };
  119. struct TSeedStream: public IInputStream {
  120. size_t DoRead(void* inbuf, size_t len) override {
  121. char* buf = (char*)inbuf;
  122. #define DO_STEP(type) \
  123. while (len >= sizeof(type)) { \
  124. WriteUnaligned<type>(buf, RandomNumber<type>()); \
  125. buf += sizeof(type); \
  126. len -= sizeof(type); \
  127. }
  128. DO_STEP(ui64);
  129. DO_STEP(ui32);
  130. DO_STEP(ui16);
  131. DO_STEP(ui8);
  132. #undef DO_STEP
  133. return buf - (char*)inbuf;
  134. }
  135. };
  136. struct TDefaultTraits {
  137. THolder<TEntropyPoolStream> EP;
  138. TSeedStream SS;
  139. inline TDefaultTraits() {
  140. Reset();
  141. }
  142. inline IInputStream& EntropyPool() noexcept {
  143. return *EP;
  144. }
  145. inline IInputStream& Seed() noexcept {
  146. return SS;
  147. }
  148. inline void Reset() noexcept {
  149. EP.Reset(new TEntropyPoolStream(THostEntropy()));
  150. }
  151. static inline TDefaultTraits& Instance() {
  152. auto res = SingletonWithPriority<TDefaultTraits, 0>();
  153. RNGInitAtForkHandlers();
  154. return *res;
  155. }
  156. };
  157. using TRandomTraits = TDefaultTraits;
  158. } // namespace
  159. IInputStream& EntropyPool() {
  160. return TRandomTraits::Instance().EntropyPool();
  161. }
  162. IInputStream& Seed() {
  163. return TRandomTraits::Instance().Seed();
  164. }
  165. void ResetEntropyPool() {
  166. TRandomTraits::Instance().Reset();
  167. }