[Wallet] Bugfix: FRT: don't terminate when keypool is empty
[bitcoinplatinum.git] / src / random.cpp
blobaa027e49c437ff6556ce49db710773a97dc640c1
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #include "random.h"
8 #include "crypto/sha512.h"
9 #include "support/cleanse.h"
10 #ifdef WIN32
11 #include "compat.h" // for Windows API
12 #include <wincrypt.h>
13 #endif
14 #include "serialize.h" // for begin_ptr(vec)
15 #include "util.h" // for LogPrint()
16 #include "utilstrencodings.h" // for GetTime()
18 #include <stdlib.h>
19 #include <limits>
21 #ifndef WIN32
22 #include <sys/time.h>
23 #endif
25 #include <openssl/err.h>
26 #include <openssl/rand.h>
28 static void RandFailure()
30 LogPrintf("Failed to read randomness, aborting\n");
31 abort();
34 static inline int64_t GetPerformanceCounter()
36 int64_t nCounter = 0;
37 #ifdef WIN32
38 QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
39 #else
40 timeval t;
41 gettimeofday(&t, NULL);
42 nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec);
43 #endif
44 return nCounter;
47 void RandAddSeed()
49 // Seed with CPU performance counter
50 int64_t nCounter = GetPerformanceCounter();
51 RAND_add(&nCounter, sizeof(nCounter), 1.5);
52 memory_cleanse((void*)&nCounter, sizeof(nCounter));
55 static void RandAddSeedPerfmon()
57 RandAddSeed();
59 #ifdef WIN32
60 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
61 // Seed with the entire set of perfmon data
63 // This can take up to 2 seconds, so only do it every 10 minutes
64 static int64_t nLastPerfmon;
65 if (GetTime() < nLastPerfmon + 10 * 60)
66 return;
67 nLastPerfmon = GetTime();
69 std::vector<unsigned char> vData(250000, 0);
70 long ret = 0;
71 unsigned long nSize = 0;
72 const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data
73 while (true) {
74 nSize = vData.size();
75 ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, begin_ptr(vData), &nSize);
76 if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)
77 break;
78 vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially
80 RegCloseKey(HKEY_PERFORMANCE_DATA);
81 if (ret == ERROR_SUCCESS) {
82 RAND_add(begin_ptr(vData), nSize, nSize / 100.0);
83 memory_cleanse(begin_ptr(vData), nSize);
84 LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
85 } else {
86 static bool warned = false; // Warn only once
87 if (!warned) {
88 LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret);
89 warned = true;
92 #endif
95 /** Get 32 bytes of system entropy. */
96 static void GetOSRand(unsigned char *ent32)
98 #ifdef WIN32
99 HCRYPTPROV hProvider;
100 int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
101 if (!ret) {
102 RandFailure();
104 ret = CryptGenRandom(hProvider, 32, ent32);
105 if (!ret) {
106 RandFailure();
108 CryptReleaseContext(hProvider, 0);
109 #else
110 int f = open("/dev/urandom", O_RDONLY);
111 if (f == -1) {
112 RandFailure();
114 int have = 0;
115 do {
116 ssize_t n = read(f, ent32 + have, 32 - have);
117 if (n <= 0 || n + have > 32) {
118 RandFailure();
120 have += n;
121 } while (have < 32);
122 close(f);
123 #endif
126 void GetRandBytes(unsigned char* buf, int num)
128 if (RAND_bytes(buf, num) != 1) {
129 RandFailure();
133 void GetStrongRandBytes(unsigned char* out, int num)
135 assert(num <= 32);
136 CSHA512 hasher;
137 unsigned char buf[64];
139 // First source: OpenSSL's RNG
140 RandAddSeedPerfmon();
141 GetRandBytes(buf, 32);
142 hasher.Write(buf, 32);
144 // Second source: OS RNG
145 GetOSRand(buf);
146 hasher.Write(buf, 32);
148 // Produce output
149 hasher.Finalize(buf);
150 memcpy(out, buf, num);
151 memory_cleanse(buf, 64);
154 uint64_t GetRand(uint64_t nMax)
156 if (nMax == 0)
157 return 0;
159 // The range of the random source must be a multiple of the modulus
160 // to give every possible output value an equal possibility
161 uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;
162 uint64_t nRand = 0;
163 do {
164 GetRandBytes((unsigned char*)&nRand, sizeof(nRand));
165 } while (nRand >= nRange);
166 return (nRand % nMax);
169 int GetRandInt(int nMax)
171 return GetRand(nMax);
174 uint256 GetRandHash()
176 uint256 hash;
177 GetRandBytes((unsigned char*)&hash, sizeof(hash));
178 return hash;
181 FastRandomContext::FastRandomContext(bool fDeterministic)
183 // The seed values have some unlikely fixed points which we avoid.
184 if (fDeterministic) {
185 Rz = Rw = 11;
186 } else {
187 uint32_t tmp;
188 do {
189 GetRandBytes((unsigned char*)&tmp, 4);
190 } while (tmp == 0 || tmp == 0x9068ffffU);
191 Rz = tmp;
192 do {
193 GetRandBytes((unsigned char*)&tmp, 4);
194 } while (tmp == 0 || tmp == 0x464fffffU);
195 Rw = tmp;