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