File Coverage

csprng.c
Criterion Covered Total %
statement 82 83 98.8
branch 23 24 95.8
condition n/a
subroutine n/a
pod n/a
total 105 107 98.1


line stmt bran cond sub pod time code
1              
2             /* Our API for random numbers.
3             *
4             * We can use ISAAC, ChaCha20, or something else.
5             *
6             * 3700 ns/word ChaCha20 in Perl
7             * 3100 ns/word Salsa20 in Perl
8             * 1600 ns/word ChaCha8 in Perl
9             * 760 ns/word ISAAC in Perl
10             *
11             * 11.20 ns/word ChaCha20 (openbsd)
12             * 10.31 ns/word ChaCha20 (dj)
13             * 8.66 ns/word ChaCha20 (sse2 Peters)
14             * 6.85 ns/word ChaCha12 (dj)
15             * 5.99 ns/word Tyche
16             * 5.11 ns/word ChaCha8 (dj)
17             * 4.37 ns/word MT19937 (Cokus)
18             * 4.14 ns/word Tyche-i
19             * 3.26 ns/word ISAAC
20             * 3.18 ns/word PCG64 (64-bit state, 64-bit types)
21             * 1.95 ns/word PCG64 (64-bit state, 128-bit types)
22             * 1.84 ns/word ChaCha20 (AVX2 chacha-opt)
23             * 1.48 ns/word Xoroshiro128+
24             * 1.16 ns/word SplitMix64
25             *
26             * These functions do locking, the underlying library does not.
27             */
28              
29             #include
30             #include
31             #include
32             #include "ptypes.h"
33             #include "csprng.h"
34              
35             #include "chacha.h"
36             #define SEED_BYTES (32+8)
37             #define CSEED(ctx,bytes,data,good) chacha_seed((chacha_context_t*)ctx,bytes,data,good)
38             #define CRBYTES(ctx,bytes,data) chacha_rand_bytes((chacha_context_t*)ctx,bytes,data)
39             #define CIRAND32(ctx) chacha_irand32((chacha_context_t*)ctx)
40             #define CIRAND64(ctx) chacha_irand64((chacha_context_t*)ctx)
41             #define CSELFTEST() chacha_selftest()
42              
43             /* Helper macros, similar to ChaCha, so we're consistent. */
44             #if !defined(__x86_64__)
45             #undef U8TO32_LE
46             #undef U32TO8_LE
47             #endif
48             #ifndef U8TO32_LE
49             #define U8TO32_LE(p) \
50             ((uint32_t)(p)[0] | \
51             (uint32_t)(p)[1] << 8 | \
52             (uint32_t)(p)[2] << 16 | \
53             (uint32_t)(p)[3] << 24)
54             #endif
55             #ifndef U32TO8_LE
56             #define U32TO8_LE(p, v) \
57             do { uint32_t _v = v; \
58             (p)[0] = _v & 0xFF; \
59             (p)[1] = _v >> 8 & 0xFF; \
60             (p)[2] = _v >> 16 & 0xFF; \
61             (p)[3] = _v >> 24 & 0xFF; \
62             } while (0)
63             #endif
64              
65             /*****************************************************************************/
66              
67             /* We put a simple 32-bit non-CS PRNG here to help fill small seeds. */
68             #if 0
69             /* XOSHIRO128** 32-bit output, 32-bit types, 128-bit state */
70             static INLINE uint32_t rotl(const uint32_t x, int k) {
71             return (x << k) | (x >> (32 - k));
72             }
73             uint32_t prng_next(void* ctx) {
74             uint32_t *s = (uint32_t*) ctx;
75             const uint32_t result_starstar = rotl(s[0] * 5, 7) * 9;
76             const uint32_t t = s[1] << 9;
77             s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3];
78             s[2] ^= t;
79             s[3] = rotl(s[3], 11);
80             return result_starstar;
81             }
82             void* prng_new(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
83             uint32_t *state;
84             New(0, state, 4, uint32_t);
85             state[0] = 1; state[1] = b; state[2] = c; state[3] = d;
86             (void) prng_next((void*)state);
87             state[0] += a;
88             (void) prng_next((void*)state);
89             return (void*) state;
90             }
91             #else
92             /* PCG RXS M XS 32. 32-bit output, 32-bit state and types. */
93 116           uint32_t prng_next(void* ctx) {
94 116           uint32_t *rng = (uint32_t*) ctx;
95 116           uint32_t word, oldstate = rng[0];
96 116           rng[0] = rng[0] * 747796405U + rng[1];
97 116           word = ((oldstate >> ((oldstate >> 28u) + 4u)) ^ oldstate) * 277803737u;
98 116           return (word >> 22u) ^ word;
99             }
100 9           void* prng_new(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
101             uint32_t *state;
102 9           New(0, state, 2, uint32_t);
103 9           state[0] = 0U;
104 9           state[1] = (b << 1u) | 1u;
105 9           (void) prng_next((void*)state);
106 9           state[0] += a;
107 9           (void) prng_next((void*)state);
108 9           state[0] ^= c;
109 9           (void) prng_next((void*)state);
110 9           state[0] ^= d;
111 9           (void) prng_next((void*)state);
112 9           return (void*) state;
113             }
114             #endif
115              
116             /*****************************************************************************/
117              
118 120           uint32_t csprng_context_size(void)
119             {
120 120           return sizeof(chacha_context_t);
121             }
122             static char _has_selftest_run = 0;
123              
124 136           void csprng_seed(void *ctx, uint32_t bytes, const unsigned char* data)
125             {
126             unsigned char seed[SEED_BYTES + 4];
127              
128             /* If given a short seed, minimize zeros in state */
129 136 100         if (bytes >= SEED_BYTES) {
130 127           memcpy(seed, data, SEED_BYTES);
131             } else {
132             void* rng;
133             uint32_t a, b, c, d, i;
134 9           memcpy(seed, data, bytes);
135 9           memset(seed+bytes, 0, sizeof(seed)-bytes);
136 9           a = U8TO32_LE(seed + 0);
137 9           b = U8TO32_LE(seed + 4);
138 9           c = U8TO32_LE(seed + 8);
139 9           d = U8TO32_LE(seed + 12);
140 9           rng = prng_new(a,b,c,d);
141 89 100         for (i = 4*((bytes+3)/4); i < SEED_BYTES; i += 4)
142 80           U32TO8_LE(seed + i, prng_next(rng));
143 9           Safefree(rng);
144             #if 0
145             printf("got %u bytes in expanded to %u\n", bytes, SEED_BYTES);
146             printf("from: ");for(i=0;i
147             printf("to: ");for(i=0;i
148             #endif
149             }
150              
151 136 100         if (!_has_selftest_run) {
152 120           _has_selftest_run = 1;
153 120           CSELFTEST();
154             }
155 136           CSEED(ctx, SEED_BYTES, seed, (bytes >= 16));
156 136           }
157              
158 5           extern void csprng_srand(void* ctx, UV insecure_seed)
159             {
160             #if BITS_PER_WORD == 32
161             unsigned char seed[4] = {0};
162             U32TO8_LE(seed, insecure_seed);
163             csprng_seed(ctx, 4, seed);
164             #else
165 5           unsigned char seed[8] = {0};
166 5 100         if (insecure_seed <= UVCONST(4294967295)) {
167 4           U32TO8_LE(seed, insecure_seed);
168 4           csprng_seed(ctx, 4, seed);
169             } else {
170 1           U32TO8_LE(seed, insecure_seed);
171 1           U32TO8_LE(seed + 4, (insecure_seed >> 32));
172 1           csprng_seed(ctx, 8, seed);
173             }
174             #endif
175 5           }
176              
177 33           void csprng_rand_bytes(void* ctx, uint32_t bytes, unsigned char* data)
178             {
179 33           CRBYTES(ctx, bytes, data);
180 33           }
181              
182 110950           uint32_t irand32(void* ctx)
183             {
184 110950           return CIRAND32(ctx);
185             }
186 11151           UV irand64(void* ctx)
187             {
188             #if BITS_PER_WORD < 64
189             croak("irand64 too many bits for UV");
190             #else
191 11151           return CIRAND64(ctx);
192             #endif
193             }
194              
195              
196             /*****************************************************************************/
197              
198 1           bool is_csprng_well_seeded(void *ctx)
199             {
200 1           chacha_context_t *cs = (chacha_context_t*)ctx;
201 1           return cs->goodseed;
202             }
203              
204             /* There are many ways to get floats from integers. A few good, many bad.
205             *
206             * Vigna in https://prng.di.unimi.it recommends this C99:
207             * #include
208             * (x64 >> 11) * 0x1.0p-53
209             * Or the older:
210             * (x64 >> 11) * (1.0 / (1ULL<<53)).
211             *
212             * Also see alternatives discussed:
213             * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/speed-up-real.html
214             *
215             * Melissa O'Neill notes the problem is harder than it looks, doesn't address.
216             * http://www.pcg-random.org/pdf/toms-oneill-pcg-family-v1.02.pdf
217             *
218             * randomstate for numpy uses separate code for each generator.
219             * With the exception of dSFMT, they each one one of:
220             * (x64 >> 11) * (1 / 9007199254740992.0)
221             * ((x32 >> 5) * 67108864.0 + (y32 >> 6)) / 9007199254740992.0
222             * where the first one is identical to Vigna.
223             *
224             * David Jones recommends the minor 32-bit variant:
225             * ((x32 >> 6) * 134217728.0 + (y32 >> 5)) / 9007199254740992.0
226             * http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf
227             *
228             * Taylor Campbell discusses this in:
229             * http://mumble.net/~campbell/tmp/random_real.c
230             * He points out that there are two common non-broken choices,
231             * div by 2^-53 or div by 2^-64, and each are slightly flawed in
232             * different ways. He shows a theoretically better method.
233             */
234              
235             /*
236             * We prefer the x64 / 2^-64 method. It seems to produce the best results
237             * and is easiest for ensuring we fill up all the bits.
238             * It is similar to what Geoff Kuenning does in MTwist, though he computes
239             * the constants at runtime to ensure a dodgy compiler won't munge them.
240             *
241             * As of C99 or MSVC 15.6, we could better write these as e.g. 0x1.0p-64.
242             */
243             #define TO_NV_32 2.3283064365386962890625000000000000000E-10L
244             #define TO_NV_64 5.4210108624275221700372640043497085571E-20L
245             #define TO_NV_96 1.2621774483536188886587657044524579675E-29L
246             #define TO_NV_128 2.9387358770557187699218413430556141945E-39L
247              
248             #define DRAND_32_32 (CIRAND32(ctx) * TO_NV_32)
249             #define DRAND_64_32 (((CIRAND32(ctx)>>5) * 67108864.0 + (CIRAND32(ctx)>>6)) / 9007199254740992.0)
250             #define DRAND_64_64 (CIRAND64(ctx) * TO_NV_64)
251             #define DRAND_128_32 (CIRAND32(ctx) * TO_NV_32 + CIRAND32(ctx) * TO_NV_64 + CIRAND32(ctx) * TO_NV_96 + CIRAND32(ctx) * TO_NV_128)
252             #define DRAND_128_64 (CIRAND64(ctx) * TO_NV_64 + CIRAND64(ctx) * TO_NV_128)
253              
254 6037           NV drand64(void* ctx)
255             {
256             NV r;
257             #if NVMANTBITS <= 32
258             r = DRAND_32_32;
259             #elif NVMANTBITS <= 64
260 6037           r = (BITS_PER_WORD <= 32) ? DRAND_64_32 : DRAND_64_64;
261             #else
262             r = (BITS_PER_WORD <= 32) ? DRAND_128_32 : DRAND_128_64;
263             #endif
264 6037           return r;
265             }
266              
267              
268             /* Return rand 32-bit/64-bit integer between 0 to n-1 inclusive
269             *
270             * https://www.pcg-random.org/posts/bounded-rands.html
271             * https://arxiv.org/pdf/1805.10941
272             *
273             * I have also tried Stephen Canon's method:
274             * https://github.com/swiftlang/swift/pull/39143
275             * which is consistently slower for me.
276             *
277             * Here we will select one:
278             *
279             * OPENBSD = DEBIASED_MODx2
280             * LEMIRE = INT_MULT_TOPT_MOPT
281             *
282             * The main issue with LEMIRE is that it *requires* full width multiplies.
283             * We still try to support old systems that may not have 64-bit.
284             * We definitely expect 64-bit systems without uint128_t support.
285             */
286              
287             /* If this is set, we will try to use Lemire / O'Neill method. */
288             #define PREFER_LEMIRE 0
289              
290             #if PREFER_LEMIRE && HAVE_UINT64
291             uint32_t urandomm32(void *ctx, uint32_t n)
292             {
293             uint32_t x, l;
294             uint64_t m;
295              
296             if (n <= 1) return 0;
297              
298             x = CIRAND32(ctx);
299             m = (uint64_t) x * (uint64_t) n;
300             l = (uint32_t) m;
301             if (l < n) {
302             uint32_t t = -n; /* t = -n % n; try to skip the mod */
303             if (t >= n) {
304             t -= n;
305             if (t >= n)
306             t %= n;
307             }
308             while (l < t) {
309             x = CIRAND32(ctx);
310             m = (uint64_t) x * (uint64_t) n;
311             l = (uint32_t) m;
312             }
313             }
314             return m >> 32;
315             }
316             #else
317 40494           uint32_t urandomm32(void *ctx, uint32_t n)
318             {
319             uint32_t r, rmin;
320              
321 40494 100         if (n <= 1) return 0;
322              
323 39473           rmin = -n % n;
324             while (1) {
325 39477           r = CIRAND32(ctx);
326 39477 100         if (r >= rmin)
327 39473           break;
328             }
329 39473           return r % n;
330             }
331             #endif
332              
333             #if PREFER_LEMIRE && HAVE_UINT64 && HAVE_UINT128
334             UV urandomm64(void *ctx, UV n)
335             {
336             uint64_t x, l;
337             uint128_t m;
338              
339             if (n <= 4294967295UL) return urandomm32(ctx,n);
340             if (n-1 == 4294967295UL) return irand32(ctx);
341              
342             x = CIRAND64(ctx);
343             m = (uint128_t) x * (uint128_t) n;
344             l = (uint64_t) m;
345             if (l < n) {
346             uint64_t t = -n; /* t = -n % n; try to skip the mod */
347             if (t >= n) {
348             t -= n;
349             if (t >= n)
350             t %= n;
351             }
352             while (l < t) {
353             x = CIRAND64(ctx);
354             m = (uint128_t) x * (uint128_t) n;
355             l = (uint64_t) m;
356             }
357             }
358             return m >> 64;
359             }
360             #else
361 30564           UV urandomm64(void* ctx, UV n)
362             {
363             UV r, rmin;
364              
365 30564 100         if (n <= 4294967295UL) return urandomm32(ctx,n);
366 131 100         if (n-1 == 4294967295UL) return irand32(ctx);
367              
368 84           rmin = -n % n;
369             while (1) {
370 89           r = CIRAND64(ctx);
371 89 100         if (r >= rmin)
372 84           break;
373             }
374 84           return r % n;
375             }
376             #endif
377              
378              
379 1939           UV urandomb(void* ctx, int nbits)
380             {
381 1939 100         if (nbits == 0) {
382 1           return 0;
383 1938 100         } else if (nbits <= 32) {
384 797           return irand32(ctx) >> (32-nbits);
385             #if BITS_PER_WORD == 64
386 1141 50         } else if (nbits <= 64) {
387 1141           return irand64(ctx) >> (64-nbits);
388             #endif
389             }
390 0           croak("irand64 too many bits for UV");
391             }