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