File Coverage

csprng.c
Criterion Covered Total %
statement 85 86 98.8
branch 21 22 95.4
condition n/a
subroutine n/a
pod n/a
total 106 108 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             #define USE_ISAAC 0
36             #define USE_CHACHA20 1
37              
38             #if (USE_ISAAC + USE_CHACHA20) != 1
39             #error Exactly one CSPRNG should been selected
40             #endif
41              
42             #if USE_ISAAC
43              
44             #include "isaac.h"
45             #define SEED_BYTES 1024
46             #define CSEED isaac_seed
47             #define CRBYTES isaac_rand_bytes
48             #define CIRAND32 isaac_irand32
49             #define CIRAND64 isaac_irand64
50             #define CSELFTEST isaac_selftest
51              
52             #elif USE_CHACHA20
53              
54             #include "chacha.h"
55             #define SEED_BYTES (32+8)
56             #define CSEED(ctx,bytes,data,good) chacha_seed(ctx,bytes,data,good)
57             #define CRBYTES(ctx,bytes,data) chacha_rand_bytes(ctx,bytes,data)
58             #define CIRAND32(ctx) chacha_irand32(ctx)
59             #define CIRAND64(ctx) chacha_irand64(ctx)
60             #define CSELFTEST() chacha_selftest()
61              
62             #endif
63              
64             /* Helper macros, similar to ChaCha, so we're consistent. */
65             #ifndef U8TO32_LE
66             #define U8TO32_LE(p) \
67             (((uint32_t)((p)[0]) ) | \
68             ((uint32_t)((p)[1]) << 8) | \
69             ((uint32_t)((p)[2]) << 16) | \
70             ((uint32_t)((p)[3]) << 24))
71             #endif
72             #define U32TO8_LE(p, v) \
73             do { \
74             uint32_t _v = v; \
75             (p)[0] = (((_v) ) & 0xFFU); \
76             (p)[1] = (((_v) >> 8) & 0xFFU); \
77             (p)[2] = (((_v) >> 16) & 0xFFU); \
78             (p)[3] = (((_v) >> 24) & 0xFFU); \
79             } while (0)
80              
81             /*****************************************************************************/
82              
83             /* We put a simple non-CS PRNG here to help fill small seeds.
84             * I'd like to use PCG64 or Xoroshiro128+ here, but to be maximally
85             * portable and reproducible, we'll use PCG (RXS M XS 32).
86             */
87             #if 0
88             /* PCG XSH RR 64/32. 32-bit output, 64-bit state and types. */
89             uint32_t prng_next(char* rng) {
90             uint32_t xorshifted, rot;
91             uint64_t *state = (uint64_t*) rng;
92             uint64_t oldstate = state[0];
93             pcg_state = oldstate * 6364136223846793005ULL + state[1];
94             xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
95             rot = oldstate >> 59u;
96             return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
97             }
98             char* prng_new(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
99             uint64_t *state, initstate, initseq;
100             New(0, state, 2, uint64_t);
101             initstate = (((uint64_t)a) << 32) | b;
102             initseq = (((uint64_t)c) << 32) | d;
103             state[0] = 0U;
104             state[1] = (initseq << 1u) | 1u;
105             (void) prng_next((char*)state);
106             state[0] += initstate;
107             (void) prng_next((char*)state);
108             return (char*) state;
109             }
110             #else
111             /* PCG RXS M XS 32. 32-bit output, 32-bit state and types. */
112 64           uint32_t prng_next(char* ctx) {
113 64           uint32_t *rng = (uint32_t*) ctx;
114 64           uint32_t word, oldstate = rng[0];
115 64           rng[0] = rng[0] * 747796405U + rng[1];
116 64           word = ((oldstate >> ((oldstate >> 28u) + 4u)) ^ oldstate) * 277803737u;
117 64           return (word >> 22u) ^ word;
118             }
119 5           char* prng_new(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
120             uint32_t *state;
121 5           New(0, state, 2, uint32_t);
122 5           state[0] = 0U;
123 5           state[1] = (b << 1u) | 1u;
124 5           (void) prng_next((char*)state);
125 5           state[0] += a;
126 5           (void) prng_next((char*)state);
127 5           state[0] ^= c;
128 5           (void) prng_next((char*)state);
129 5           state[0] ^= d;
130 5           (void) prng_next((char*)state);
131 5           return (char*) state;
132             }
133             #endif
134              
135             /*****************************************************************************/
136              
137 96           uint32_t csprng_context_size(void)
138             {
139 96           return sizeof(chacha_context_t);
140             }
141             static char _has_selftest_run = 0;
142              
143 59           void csprng_seed(void *ctx, uint32_t bytes, const unsigned char* data)
144             {
145             unsigned char seed[SEED_BYTES + 4];
146              
147             /* If given a short seed, minimize zeros in state */
148 59 100         if (bytes >= SEED_BYTES) {
149 54           memcpy(seed, data, SEED_BYTES);
150             } else {
151             char* rng;
152             uint32_t a, b, c, d, i;
153 5           memcpy(seed, data, bytes);
154 5           memset(seed+bytes, 0, sizeof(seed)-bytes);
155 5           a = U8TO32_LE((seed + 0));
156 5           b = U8TO32_LE((seed + 4));
157 5           c = U8TO32_LE((seed + 8));
158 5           d = U8TO32_LE((seed + 12));
159 5           rng = prng_new(a,b,c,d);
160 49 100         for (i = 4*((bytes+3)/4); i < SEED_BYTES; i += 4)
161 44           U32TO8_LE(seed + i, prng_next(rng));
162 5           Safefree(rng);
163             #if 0
164             printf("got %u bytes in expanded to %u\n", bytes, SEED_BYTES);
165             printf("from: ");for(i=0;i
166             printf("to: ");for(i=0;i
167             #endif
168             }
169              
170 59 100         if (!_has_selftest_run) {
171 48           _has_selftest_run = 1;
172 48           CSELFTEST();
173             }
174 59           CSEED(ctx, SEED_BYTES, seed, (bytes >= 16));
175 59           }
176              
177 5           extern void csprng_srand(void* ctx, UV insecure_seed)
178             {
179             #if BITS_PER_WORD == 32
180             unsigned char seed[4] = {0};
181             U32TO8_LE(seed, insecure_seed);
182             csprng_seed(ctx, 4, seed);
183             #else
184 5           unsigned char seed[8] = {0};
185 5 100         if (insecure_seed <= UVCONST(4294967295)) {
186 4           U32TO8_LE(seed, insecure_seed);
187 4           csprng_seed(ctx, 4, seed);
188             } else {
189 1           U32TO8_LE(seed, insecure_seed);
190 1           U32TO8_LE(seed + 4, (insecure_seed >> 32));
191 1           csprng_seed(ctx, 8, seed);
192             }
193             #endif
194 5           }
195              
196 37           void csprng_rand_bytes(void* ctx, uint32_t bytes, unsigned char* data)
197             {
198 37           CRBYTES(ctx, bytes, data);
199 37           }
200              
201 100801           uint32_t irand32(void* ctx)
202             {
203 100801           return CIRAND32(ctx);
204             }
205 2452           UV irand64(void* ctx)
206             {
207             #if BITS_PER_WORD < 64
208             croak("irand64 too many bits for UV");
209             #else
210 2452           return CIRAND64(ctx);
211             #endif
212             }
213              
214              
215             /*****************************************************************************/
216              
217 1           int is_csprng_well_seeded(void *ctx)
218             {
219 1           chacha_context_t *cs = ctx;
220 1           return cs->goodseed;
221             }
222              
223             /* There are many ways to get floats from integers. A few good, many bad.
224             *
225             * Vigna recommends (x64 >> 11) * (1.0 / (1ULL<<53)).
226             * http://xoroshiro.di.unimi.it
227             * Also see alternatives discussed:
228             * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/speed-up-real.html
229             *
230             * Melissa O'Neill notes the problem is harder than it looks, doesn't address.
231             * http://www.pcg-random.org/pdf/toms-oneill-pcg-family-v1.02.pdf
232             *
233             * randomstate for numpy uses separate code for each generator.
234             * With the exception of dSFMT, they each one one of:
235             * (x64 >> 11) * (1 / 9007199254740992.0)
236             * ((x32 >> 5) * 67108864.0 + (y32 >> 6)) / 9007199254740992.0
237             * where the first one is identical to Vigna.
238             *
239             * David Jones recommends the minor 32-bit variant:
240             * ((x32 >> 6) * 134217728.0 + (y32 >> 5)) / 9007199254740992.0
241             * http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf
242             *
243             * Taylor Campbell discusses this in:
244             * http://mumble.net/~campbell/tmp/random_real.c
245             * He points out that there are two common non-broken choices,
246             * div by 2^-53 or div by 2^-64, and each are slightly flawed in
247             * different ways. He shows a theoretically better method.
248             */
249              
250             /*
251             * We prefer the x64 / 2^-64 method. It seems to produce the best results
252             * and is easiest for ensuring we fill up all the bits.
253             * It is similar to what Geoff Kuenning does in MTwist, though he computes
254             * the constants at runtime to ensure a dodgy compiler won't munge them.
255             */
256             #define TO_NV_32 2.3283064365386962890625000000000000000E-10L
257             #define TO_NV_64 5.4210108624275221700372640043497085571E-20L
258             #define TO_NV_96 1.2621774483536188886587657044524579675E-29L
259             #define TO_NV_128 2.9387358770557187699218413430556141945E-39L
260              
261             #define DRAND_32_32 (CIRAND32(ctx) * TO_NV_32)
262             #define DRAND_64_32 (((CIRAND32(ctx)>>5) * 67108864.0 + (CIRAND32(ctx)>>6)) / 9007199254740992.0)
263             #define DRAND_64_64 (CIRAND64(ctx) * TO_NV_64)
264             #define DRAND_128_32 (CIRAND32(ctx) * TO_NV_32 + CIRAND32(ctx) * TO_NV_64 + CIRAND32(ctx) * TO_NV_96 + CIRAND32(ctx) * TO_NV_128)
265             #define DRAND_128_64 (CIRAND64(ctx) * TO_NV_64 + CIRAND64(ctx) * TO_NV_128)
266              
267 6038           NV drand64(void* ctx)
268             {
269             NV r;
270             #if NVMANTBITS <= 32
271             r = DRAND_32_32;
272             #elif NVMANTBITS <= 64
273 6038           r = (BITS_PER_WORD <= 32) ? DRAND_64_32 : DRAND_64_64;
274             #else
275             r = (BITS_PER_WORD <= 32) ? DRAND_128_32 : DRAND_128_64;
276             #endif
277 6038           return r;
278             }
279              
280             /* Return rand 32-bit integer between 0 to n-1 inclusive */
281 133008           uint32_t urandomm32(void *ctx, uint32_t n)
282             {
283             uint32_t r, rmin;
284              
285 133008 100         if (n <= 1)
286 1010           return 0;
287              
288 131998           rmin = -n % n;
289             while (1) {
290 132001           r = CIRAND32(ctx);
291 132001 100         if (r >= rmin)
292 131998           break;
293 3           }
294 131998           return r % n;
295             }
296              
297 133144           UV urandomm64(void* ctx, UV n)
298             {
299             UV r, rmin;
300              
301 133144 100         if (n <= 4294967295UL)
302 132886           return urandomm32(ctx,n);
303              
304 258           rmin = -n % n;
305             while (1) {
306 259           r = CIRAND64(ctx);
307 259 100         if (r >= rmin)
308 258           break;
309 1           }
310 258           return r % n;
311             }
312              
313 3243           UV urandomb(void* ctx, int nbits)
314             {
315 3243 100         if (nbits == 0) {
316 1           return 0;
317 3242 100         } else if (nbits <= 32) {
318 796           return irand32(ctx) >> (32-nbits);
319             #if BITS_PER_WORD == 64
320 2446 50         } else if (nbits <= 64) {
321 2446           return irand64(ctx) >> (64-nbits);
322             #endif
323             }
324 0           croak("irand64 too many bits for UV");
325             }