line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
To the extent possible under law, the author has dedicated all copyright |
4
|
|
|
|
|
|
|
and related and neighboring rights to this software to the public domain |
5
|
|
|
|
|
|
|
worldwide. This software is distributed without any warranty. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
See . */ |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#include "git2_util.h" |
10
|
|
|
|
|
|
|
#include "rand.h" |
11
|
|
|
|
|
|
|
#include "runtime.h" |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#if defined(GIT_RAND_GETENTROPY) |
14
|
|
|
|
|
|
|
# include |
15
|
|
|
|
|
|
|
#endif |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
static uint64_t state[4]; |
18
|
|
|
|
|
|
|
static git_mutex state_lock; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
typedef union { |
21
|
|
|
|
|
|
|
double f; |
22
|
|
|
|
|
|
|
uint64_t d; |
23
|
|
|
|
|
|
|
} bits; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#if defined(GIT_WIN32) |
26
|
|
|
|
|
|
|
GIT_INLINE(int) getseed(uint64_t *seed) |
27
|
|
|
|
|
|
|
{ |
28
|
|
|
|
|
|
|
HCRYPTPROV provider; |
29
|
|
|
|
|
|
|
SYSTEMTIME systemtime; |
30
|
|
|
|
|
|
|
FILETIME filetime, idletime, kerneltime, usertime; |
31
|
|
|
|
|
|
|
bits convert; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, |
34
|
|
|
|
|
|
|
CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { |
35
|
|
|
|
|
|
|
BOOL success = CryptGenRandom(provider, sizeof(uint64_t), (void *)seed); |
36
|
|
|
|
|
|
|
CryptReleaseContext(provider, 0); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
if (success) |
39
|
|
|
|
|
|
|
return 0; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
GetSystemTime(&systemtime); |
43
|
|
|
|
|
|
|
if (!SystemTimeToFileTime(&systemtime, &filetime)) { |
44
|
|
|
|
|
|
|
git_error_set(GIT_ERROR_OS, "could not get time for random seed"); |
45
|
|
|
|
|
|
|
return -1; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
/* Fall-through: generate a seed from the time and system state */ |
49
|
|
|
|
|
|
|
*seed = 0; |
50
|
|
|
|
|
|
|
*seed |= ((uint64_t)filetime.dwLowDateTime << 32); |
51
|
|
|
|
|
|
|
*seed |= ((uint64_t)filetime.dwHighDateTime); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
GetSystemTimes(&idletime, &kerneltime, &usertime); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
*seed ^= ((uint64_t)idletime.dwLowDateTime << 32); |
56
|
|
|
|
|
|
|
*seed ^= ((uint64_t)kerneltime.dwLowDateTime); |
57
|
|
|
|
|
|
|
*seed ^= ((uint64_t)usertime.dwLowDateTime << 32); |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
*seed ^= ((uint64_t)idletime.dwHighDateTime); |
60
|
|
|
|
|
|
|
*seed ^= ((uint64_t)kerneltime.dwHighDateTime << 12); |
61
|
|
|
|
|
|
|
*seed ^= ((uint64_t)usertime.dwHighDateTime << 24); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
*seed ^= ((uint64_t)GetCurrentProcessId() << 32); |
64
|
|
|
|
|
|
|
*seed ^= ((uint64_t)GetCurrentThreadId() << 48); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
convert.f = git__timer(); *seed ^= (convert.d); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
/* Mix in the addresses of some functions and variables */ |
69
|
|
|
|
|
|
|
*seed ^= (((uint64_t)((uintptr_t)seed) << 32)); |
70
|
|
|
|
|
|
|
*seed ^= (((uint64_t)((uintptr_t)&errno))); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
return 0; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
#else |
76
|
|
|
|
|
|
|
|
77
|
87
|
|
|
|
|
|
GIT_INLINE(int) getseed(uint64_t *seed) |
78
|
|
|
|
|
|
|
{ |
79
|
|
|
|
|
|
|
struct timeval tv; |
80
|
|
|
|
|
|
|
double loadavg[3]; |
81
|
|
|
|
|
|
|
bits convert; |
82
|
|
|
|
|
|
|
int fd; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# if defined(GIT_RAND_GETENTROPY) |
85
|
|
|
|
|
|
|
GIT_UNUSED((fd = 0)); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
if (getentropy(seed, sizeof(uint64_t)) == 0) |
88
|
|
|
|
|
|
|
return 0; |
89
|
|
|
|
|
|
|
# else |
90
|
|
|
|
|
|
|
/* |
91
|
|
|
|
|
|
|
* Try to read from /dev/urandom; most modern systems will have |
92
|
|
|
|
|
|
|
* this, but we may be chrooted, etc, so it's not a fatal error |
93
|
|
|
|
|
|
|
*/ |
94
|
87
|
50
|
|
|
|
|
if ((fd = open("/dev/urandom", O_RDONLY)) >= 0) { |
95
|
87
|
|
|
|
|
|
ssize_t ret = read(fd, seed, sizeof(uint64_t)); |
96
|
87
|
|
|
|
|
|
close(fd); |
97
|
|
|
|
|
|
|
|
98
|
87
|
50
|
|
|
|
|
if (ret == (ssize_t)sizeof(uint64_t)) |
99
|
87
|
|
|
|
|
|
return 0; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
# endif |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
/* Fall-through: generate a seed from the time and system state */ |
104
|
0
|
0
|
|
|
|
|
if (gettimeofday(&tv, NULL) < 0) { |
105
|
0
|
|
|
|
|
|
git_error_set(GIT_ERROR_OS, "could get time for random seed"); |
106
|
0
|
|
|
|
|
|
return -1; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
*seed = 0; |
110
|
0
|
|
|
|
|
|
*seed |= ((uint64_t)tv.tv_usec << 40); |
111
|
0
|
|
|
|
|
|
*seed |= ((uint64_t)tv.tv_sec); |
112
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getpid() << 48); |
114
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getppid() << 32); |
115
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getpgid(0) << 28); |
116
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getsid(0) << 16); |
117
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getuid() << 8); |
118
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getgid()); |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# if defined(GIT_RAND_GETLOADAVG) |
121
|
|
|
|
|
|
|
getloadavg(loadavg, 3); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
convert.f = loadavg[0]; *seed ^= (convert.d >> 36); |
124
|
|
|
|
|
|
|
convert.f = loadavg[1]; *seed ^= (convert.d); |
125
|
|
|
|
|
|
|
convert.f = loadavg[2]; *seed ^= (convert.d >> 16); |
126
|
|
|
|
|
|
|
# else |
127
|
0
|
|
|
|
|
|
GIT_UNUSED(loadavg[0]); |
128
|
|
|
|
|
|
|
# endif |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
convert.f = git__timer(); *seed ^= (convert.d); |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
/* Mix in the addresses of some variables */ |
133
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)((size_t)((void *)seed)) << 32); |
134
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)((size_t)((void *)&errno))); |
135
|
|
|
|
|
|
|
|
136
|
87
|
|
|
|
|
|
return 0; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
#endif |
139
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
|
static void git_rand_global_shutdown(void) |
141
|
|
|
|
|
|
|
{ |
142
|
0
|
|
|
|
|
|
git_mutex_free(&state_lock); |
143
|
0
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
87
|
|
|
|
|
|
int git_rand_global_init(void) |
146
|
|
|
|
|
|
|
{ |
147
|
87
|
|
|
|
|
|
uint64_t seed = 0; |
148
|
|
|
|
|
|
|
|
149
|
87
|
50
|
|
|
|
|
if (git_mutex_init(&state_lock) < 0 || getseed(&seed) < 0) |
|
|
50
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
return -1; |
151
|
|
|
|
|
|
|
|
152
|
87
|
50
|
|
|
|
|
if (!seed) { |
153
|
0
|
|
|
|
|
|
git_error_set(GIT_ERROR_INTERNAL, "failed to generate random seed"); |
154
|
0
|
|
|
|
|
|
return -1; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
87
|
|
|
|
|
|
git_rand_seed(seed); |
158
|
87
|
|
|
|
|
|
git_runtime_shutdown_register(git_rand_global_shutdown); |
159
|
|
|
|
|
|
|
|
160
|
87
|
|
|
|
|
|
return 0; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
/* |
164
|
|
|
|
|
|
|
* This is splitmix64. xoroshiro256** uses 256 bit seed; this is used |
165
|
|
|
|
|
|
|
* to generate 256 bits of seed from the given 64, per the author's |
166
|
|
|
|
|
|
|
* recommendation. |
167
|
|
|
|
|
|
|
*/ |
168
|
348
|
|
|
|
|
|
GIT_INLINE(uint64_t) splitmix64(uint64_t *in) |
169
|
|
|
|
|
|
|
{ |
170
|
|
|
|
|
|
|
uint64_t z; |
171
|
|
|
|
|
|
|
|
172
|
348
|
|
|
|
|
|
*in += 0x9e3779b97f4a7c15; |
173
|
|
|
|
|
|
|
|
174
|
348
|
|
|
|
|
|
z = *in; |
175
|
348
|
|
|
|
|
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; |
176
|
348
|
|
|
|
|
|
z = (z ^ (z >> 27)) * 0x94d049bb133111eb; |
177
|
348
|
|
|
|
|
|
return z ^ (z >> 31); |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
87
|
|
|
|
|
|
void git_rand_seed(uint64_t seed) |
181
|
|
|
|
|
|
|
{ |
182
|
|
|
|
|
|
|
uint64_t mixer; |
183
|
|
|
|
|
|
|
|
184
|
87
|
|
|
|
|
|
mixer = seed; |
185
|
|
|
|
|
|
|
|
186
|
87
|
|
|
|
|
|
git_mutex_lock(&state_lock); |
187
|
87
|
|
|
|
|
|
state[0] = splitmix64(&mixer); |
188
|
87
|
|
|
|
|
|
state[1] = splitmix64(&mixer); |
189
|
87
|
|
|
|
|
|
state[2] = splitmix64(&mixer); |
190
|
87
|
|
|
|
|
|
state[3] = splitmix64(&mixer); |
191
|
87
|
|
|
|
|
|
git_mutex_unlock(&state_lock); |
192
|
87
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid |
195
|
|
|
|
|
|
|
generators. It has excellent (sub-ns) speed, a state (256 bits) that is |
196
|
|
|
|
|
|
|
large enough for any parallel application, and it passes all tests we |
197
|
|
|
|
|
|
|
are aware of. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
For generating just floating-point numbers, xoshiro256+ is even faster. |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
The state must be seeded so that it is not everywhere zero. If you have |
202
|
|
|
|
|
|
|
a 64-bit seed, we suggest to seed a splitmix64 generator and use its |
203
|
|
|
|
|
|
|
output to fill s. */ |
204
|
|
|
|
|
|
|
|
205
|
374
|
|
|
|
|
|
GIT_INLINE(uint64_t) rotl(const uint64_t x, int k) { |
206
|
374
|
|
|
|
|
|
return (x << k) | (x >> (64 - k)); |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
187
|
|
|
|
|
|
uint64_t git_rand_next(void) { |
210
|
|
|
|
|
|
|
uint64_t t, result; |
211
|
|
|
|
|
|
|
|
212
|
187
|
|
|
|
|
|
git_mutex_lock(&state_lock); |
213
|
|
|
|
|
|
|
|
214
|
187
|
|
|
|
|
|
result = rotl(state[1] * 5, 7) * 9; |
215
|
|
|
|
|
|
|
|
216
|
187
|
|
|
|
|
|
t = state[1] << 17; |
217
|
|
|
|
|
|
|
|
218
|
187
|
|
|
|
|
|
state[2] ^= state[0]; |
219
|
187
|
|
|
|
|
|
state[3] ^= state[1]; |
220
|
187
|
|
|
|
|
|
state[1] ^= state[2]; |
221
|
187
|
|
|
|
|
|
state[0] ^= state[3]; |
222
|
|
|
|
|
|
|
|
223
|
187
|
|
|
|
|
|
state[2] ^= t; |
224
|
|
|
|
|
|
|
|
225
|
187
|
|
|
|
|
|
state[3] = rotl(state[3], 45); |
226
|
|
|
|
|
|
|
|
227
|
187
|
|
|
|
|
|
git_mutex_unlock(&state_lock); |
228
|
|
|
|
|
|
|
|
229
|
187
|
|
|
|
|
|
return result; |
230
|
|
|
|
|
|
|
} |