varnish-cache/lib/libvarnish/vrnd.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * Copyright (c) 1983, 1993 The Regents of the University of California.
5
 * All rights reserved.
6
 *
7
 * Author: Dag-Erling Smørgrav <des@des.no>
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * Partially from: $FreeBSD: head/lib/libc/stdlib/random.c 303342
31
 *
32
 */
33
34
#include "config.h"
35
36
#include <fcntl.h>
37
#include <math.h>
38
#include <stdint.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#include "vdef.h"
44
45
#include "vas.h"
46
#include "vrnd.h"
47
48
49
vrnd_lock_f *VRND_Lock;
50
vrnd_lock_f *VRND_Unlock;
51
52
/**********************************************************************
53
 * Stripped down random(3) implementation from FreeBSD, to provide
54
 * predicatable "random" numbers of testing purposes.
55
 */
56
57
#define TYPE_3          3               /* x**31 + x**3 + 1 */
58
#define DEG_3           31
59
#define SEP_3           3
60
61
static uint32_t randtbl[DEG_3 + 1] = {
62
        TYPE_3,
63
        0x2cf41758, 0x27bb3711, 0x4916d4d1, 0x7b02f59f, 0x9b8e28eb, 0xc0e80269,
64
        0x696f5c16, 0x878f1ff5, 0x52d9c07f, 0x916a06cd, 0xb50b3a20, 0x2776970a,
65
        0xee4eb2a6, 0xe94640ec, 0xb1d65612, 0x9d1ed968, 0x1043f6b7, 0xa3432a76,
66
        0x17eacbb9, 0x3c09e2eb, 0x4f8c2b3,  0x708a1f57, 0xee341814, 0x95d0e4d2,
67
        0xb06f216c, 0x8bd2e72e, 0x8f7c38d7, 0xcfc6a8fc, 0x2a59495,  0xa20d2a69,
68
        0xe29d12d1
69
};
70
71
static uint32_t *fptr = &randtbl[SEP_3 + 1];
72
static uint32_t *rptr = &randtbl[1];
73
74
static uint32_t * const state = &randtbl[1];
75
static const int rand_deg = DEG_3;
76
static const int rand_sep = SEP_3;
77
static const uint32_t * const end_ptr = &randtbl[DEG_3 + 1];
78
79
static inline uint32_t
80 1075680
good_rand(uint32_t ctx)
81
{
82
/*
83
 * Compute x = (7^5 * x) mod (2^31 - 1)
84
 * wihout overflowing 31 bits:
85
 *      (2^31 - 1) = 127773 * (7^5) + 2836
86
 * From "Random number generators: good ones are hard to find",
87
 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
88
 * October 1988, p. 1195.
89
 */
90
        int32_t hi, lo, x;
91
92
        /* Transform to [1, 0x7ffffffe] range. */
93 1075680
        x = (ctx % 0x7ffffffe) + 1;
94 1075680
        hi = x / 127773;
95 1075680
        lo = x % 127773;
96 1075680
        x = 16807 * lo - 2836 * hi;
97 1075680
        if (x < 0)
98 11775
                x += 0x7fffffff;
99
        /* Transform to [0, 0x7ffffffd] range. */
100 1075680
        return (x - 1);
101
}
102
103
static long
104 50962079
vrnd_RandomTestable(void)
105
{
106
        uint32_t i;
107
        uint32_t *f, *r;
108
109
        /*
110
         * Use local variables rather than static variables for speed.
111
         */
112 50962079
        f = fptr; r = rptr;
113 50962079
        *f += *r;
114 50962079
        i = *f >> 1;    /* chucking least random bit */
115 50962079
        if (++f >= end_ptr) {
116 1643878
                f = state;
117 1643878
                ++r;
118
        }
119 49318201
        else if (++r >= end_ptr) {
120 1643868
                r = state;
121
        }
122
123 50962079
        fptr = f; rptr = r;
124 50962079
        return ((long)i);
125
}
126
127
128
void
129 35856
VRND_SeedTestable(unsigned int x)
130
{
131
        int i, lim;
132
133 35856
        state[0] = (uint32_t)x;
134 1111536
        for (i = 1; i < rand_deg; i++)
135 1075680
                state[i] = good_rand(state[i - 1]);
136 35856
        fptr = &state[rand_sep];
137 35856
        rptr = &state[0];
138 35856
        lim = 10 * rand_deg;
139 11151216
        for (i = 0; i < lim; i++)
140 11115360
                (void)vrnd_RandomTestable();
141 35856
}
142
143
long
144 39846719
VRND_RandomTestable(void)
145
{
146
        long l;
147
148 39846719
        AN(VRND_Lock);
149 39846719
        VRND_Lock();
150 39846719
        l = vrnd_RandomTestable();
151 39846719
        AN(VRND_Unlock);
152 39846719
        VRND_Unlock();
153 39846719
        return (l);
154
}
155
156
double
157 924
VRND_RandomTestableDouble(void)
158
{
159
        return (
160 1848
                ldexp((double)VRND_RandomTestable(), -31) +
161 924
                ldexp((double)VRND_RandomTestable(), -62)
162
        );
163
}
164
165
int
166 2931336
VRND_RandomCrypto(void *ptr, size_t len)
167
{
168
        int fd;
169
        char *p;
170
        ssize_t l;
171
172 2931336
        AN(ptr);
173 2931336
        fd = open("/dev/urandom", O_RDONLY);
174 2931254
        if (fd < 0)
175 0
                return (-1);
176 9339866
        for (p = ptr; len > 0; len--, p++) {
177 6408530
                l = read(fd, p, 1);
178 6408612
                if (l != 1)
179 0
                        break;
180
        }
181 2931336
        closefd(&fd);
182 2931336
        return (len == 0 ? 0 : -1);
183
}
184
185
void
186 35808
VRND_SeedAll(void)
187
{
188
        unsigned long seed;
189
190 35808
        AZ(VRND_RandomCrypto(&seed, sizeof seed));
191 35808
        srandom(seed);
192 35808
        AZ(VRND_RandomCrypto(&seed, sizeof seed));
193 35808
        VRND_SeedTestable(seed);
194 35808
        AZ(VRND_RandomCrypto(&seed, sizeof seed));
195 35808
        srand48(seed);
196 35808
}