Update CMakeLists.txt - play with openssl
[novacoin.git] / src / random.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "random.h"
7 #include "uint256.h"
8 #include "util.h" // for printf()
9
10 #ifdef WIN32
11 #include "compat.h" // for Windows API
12 #endif
13
14 #ifndef WIN32
15 #include <sys/time.h>
16 #endif
17
18 #include <openssl/crypto.h>
19 #include <openssl/err.h>
20 #include <openssl/rand.h>
21
22 #include <cstring>
23
24
25 static inline int64_t GetPerformanceCounter()
26 {
27     int64_t nCounter = 0;
28 #ifdef WIN32
29     QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
30 #else
31     timeval t{};
32     gettimeofday(&t, nullptr);
33     nCounter = (int64_t) t.tv_sec * 1000000 + t.tv_usec;
34 #endif
35     return nCounter;
36 }
37
38 void RandAddSeed()
39 {
40     // Seed with CPU performance counter
41     int64_t nCounter = GetPerformanceCounter();
42     RAND_add(&nCounter, sizeof(nCounter), 1.5);
43     memset(&nCounter, 0, sizeof(nCounter));
44 }
45
46 void RandAddSeedPerfmon()
47 {
48     RandAddSeed();
49
50 #ifdef WIN32
51     // This can take up to 2 seconds, so only do it every 10 minutes
52     static int64_t nLastPerfmon;
53     if (GetTime() < nLastPerfmon + 10 * 60)
54         return;
55     nLastPerfmon = GetTime();
56
57     // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
58     // Seed with the entire set of perfmon data
59     unsigned char pdata[250000];
60     memset(pdata, 0, sizeof(pdata));
61     unsigned long nSize = sizeof(pdata);
62     long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
63     RegCloseKey(HKEY_PERFORMANCE_DATA);
64     if (ret == ERROR_SUCCESS)
65     {
66         RAND_add(pdata, nSize, nSize/100.0);
67         OPENSSL_cleanse(pdata, nSize);
68         printf("RandAddSeed() %lu bytes\n", nSize);
69     }
70 #endif
71 }
72
73 void GetRandBytes(unsigned char *buf, int num)
74 {
75     if (RAND_bytes(buf, num) != 1) {
76         printf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), nullptr));
77         assert(false);
78     }
79 }
80
81 uint64_t GetRand(uint64_t nMax)
82 {
83     if (nMax == 0)
84         return 0;
85
86     // The range of the random source must be a multiple of the modulus
87     // to give every possible output value an equal possibility
88     uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;
89     uint64_t nRand = 0;
90     do
91         RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
92     while (nRand >= nRange);
93     return (nRand % nMax);
94 }
95
96 int GetRandInt(int nMax)
97 {
98     return static_cast<int>(GetRand(nMax));
99 }
100
101 uint256 GetRandHash()
102 {
103     uint256 hash;
104     RAND_bytes(hash.begin(), hash.size());
105     return hash;
106 }