]> Git Repo - VerusCoin.git/blob - src/random.cpp
Merge pull request #4599
[VerusCoin.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
8 #ifdef WIN32
9 #include "compat.h" // for Windows API
10 #endif
11 #include "serialize.h" // for begin_ptr(vec)
12 #include "util.h" // for LogPrint()
13 #include "utilstrencodings.h" // for GetTime()
14
15 #ifndef WIN32
16 #include <sys/time.h>
17 #endif
18 #include <limits>
19 #include <openssl/crypto.h>
20 #include <openssl/err.h>
21 #include <openssl/rand.h>
22
23 static inline int64_t GetPerformanceCounter()
24 {
25     int64_t nCounter = 0;
26 #ifdef WIN32
27     QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
28 #else
29     timeval t;
30     gettimeofday(&t, NULL);
31     nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec);
32 #endif
33     return nCounter;
34 }
35
36 void RandAddSeed()
37 {
38     // Seed with CPU performance counter
39     int64_t nCounter = GetPerformanceCounter();
40     RAND_add(&nCounter, sizeof(nCounter), 1.5);
41     OPENSSL_cleanse((void*)&nCounter, sizeof(nCounter));
42 }
43
44 void RandAddSeedPerfmon()
45 {
46     RandAddSeed();
47
48     // This can take up to 2 seconds, so only do it every 10 minutes
49     static int64_t nLastPerfmon;
50     if (GetTime() < nLastPerfmon + 10 * 60)
51         return;
52     nLastPerfmon = GetTime();
53
54 #ifdef WIN32
55     // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
56     // Seed with the entire set of perfmon data
57     std::vector <unsigned char> vData(250000,0);
58     long ret = 0;
59     unsigned long nSize = 0;
60     const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data
61     while (true)
62     {
63         nSize = vData.size();
64         ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, begin_ptr(vData), &nSize);
65         if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)
66             break;
67         vData.resize(std::max((vData.size()*3)/2, nMaxSize)); // Grow size of buffer exponentially
68     }
69     RegCloseKey(HKEY_PERFORMANCE_DATA);
70     if (ret == ERROR_SUCCESS)
71     {
72         RAND_add(begin_ptr(vData), nSize, nSize/100.0);
73         OPENSSL_cleanse(begin_ptr(vData), nSize);
74         LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
75     } else {
76         static bool warned = false; // Warn only once
77         if (!warned)
78         {
79             LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret);
80             warned = true;
81         }
82     }
83 #endif
84 }
85
86 bool GetRandBytes(unsigned char *buf, int num)
87 {
88     if (RAND_bytes(buf, num) != 1) {
89         LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL));
90         return false;
91     }
92     return true;
93 }
94
95 uint64_t GetRand(uint64_t nMax)
96 {
97     if (nMax == 0)
98         return 0;
99
100     // The range of the random source must be a multiple of the modulus
101     // to give every possible output value an equal possibility
102     uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;
103     uint64_t nRand = 0;
104     do {
105         GetRandBytes((unsigned char*)&nRand, sizeof(nRand));
106     } while (nRand >= nRange);
107     return (nRand % nMax);
108 }
109
110 int GetRandInt(int nMax)
111 {
112     return GetRand(nMax);
113 }
114
115 uint256 GetRandHash()
116 {
117     uint256 hash;
118     GetRandBytes((unsigned char*)&hash, sizeof(hash));
119     return hash;
120 }
121
122 uint32_t insecure_rand_Rz = 11;
123 uint32_t insecure_rand_Rw = 11;
124 void seed_insecure_rand(bool fDeterministic)
125 {
126     // The seed values have some unlikely fixed points which we avoid.
127     if(fDeterministic)
128     {
129         insecure_rand_Rz = insecure_rand_Rw = 11;
130     } else {
131         uint32_t tmp;
132         do {
133             GetRandBytes((unsigned char*)&tmp, 4);
134         } while(tmp == 0 || tmp == 0x9068ffffU);
135         insecure_rand_Rz = tmp;
136         do {
137             GetRandBytes((unsigned char*)&tmp, 4);
138         } while(tmp == 0 || tmp == 0x464fffffU);
139         insecure_rand_Rw = tmp;
140     }
141 }
This page took 0.032449 seconds and 4 git commands to generate.