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
 * Stripped down random(3) implementation from FreeBSD, to provide
50
 * predicatable "random" numbers of testing purposes.
51
 */
52
53
#define TYPE_3          3               /* x**31 + x**3 + 1 */
54
#define DEG_3           31
55
#define SEP_3           3
56
57
static uint32_t randtbl[DEG_3 + 1] = {
58
        TYPE_3,
59
        0x2cf41758, 0x27bb3711, 0x4916d4d1, 0x7b02f59f, 0x9b8e28eb, 0xc0e80269,
60
        0x696f5c16, 0x878f1ff5, 0x52d9c07f, 0x916a06cd, 0xb50b3a20, 0x2776970a,
61
        0xee4eb2a6, 0xe94640ec, 0xb1d65612, 0x9d1ed968, 0x1043f6b7, 0xa3432a76,
62
        0x17eacbb9, 0x3c09e2eb, 0x4f8c2b3,  0x708a1f57, 0xee341814, 0x95d0e4d2,
63
        0xb06f216c, 0x8bd2e72e, 0x8f7c38d7, 0xcfc6a8fc, 0x2a59495,  0xa20d2a69,
64
        0xe29d12d1
65
};
66
67
static uint32_t *fptr = &randtbl[SEP_3 + 1];
68
static uint32_t *rptr = &randtbl[1];
69
70
static uint32_t * const state = &randtbl[1];
71
static const int rand_deg = DEG_3;
72
static const int rand_sep = SEP_3;
73
static const uint32_t * const end_ptr = &randtbl[DEG_3 + 1];
74
75
static inline uint32_t
76 58770
good_rand(uint32_t ctx)
77
{
78
/*
79
 * Compute x = (7^5 * x) mod (2^31 - 1)
80
 * wihout overflowing 31 bits:
81
 *      (2^31 - 1) = 127773 * (7^5) + 2836
82
 * From "Random number generators: good ones are hard to find",
83
 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
84
 * October 1988, p. 1195.
85
 */
86
        int32_t hi, lo, x;
87
88
        /* Transform to [1, 0x7ffffffe] range. */
89 58770
        x = (ctx % 0x7ffffffe) + 1;
90 58770
        hi = x / 127773;
91 58770
        lo = x % 127773;
92 58770
        x = 16807 * lo - 2836 * hi;
93 58770
        if (x < 0)
94 624
                x += 0x7fffffff;
95
        /* Transform to [0, 0x7ffffffd] range. */
96 58770
        return (x - 1);
97
}
98
99
void
100 1959
VRND_SeedTestable(unsigned int x)
101
{
102
        int i, lim;
103
104 1959
        state[0] = (uint32_t)x;
105 60729
        for (i = 1; i < rand_deg; i++)
106 58770
                state[i] = good_rand(state[i - 1]);
107 1959
        fptr = &state[rand_sep];
108 1959
        rptr = &state[0];
109 1959
        lim = 10 * rand_deg;
110 609249
        for (i = 0; i < lim; i++)
111 607290
                (void)VRND_RandomTestable();
112 1959
}
113
114
long
115 3914922
VRND_RandomTestable(void)
116
{
117
        uint32_t i;
118
        uint32_t *f, *r;
119
120
        /*
121
         * Use local variables rather than static variables for speed.
122
         */
123 3914922
        f = fptr; r = rptr;
124 3914922
        *f += *r;
125 3914922
        i = *f >> 1;    /* chucking least random bit */
126 3914922
        if (++f >= end_ptr) {
127 126072
                f = state;
128 126072
                ++r;
129
        }
130 3788850
        else if (++r >= end_ptr) {
131 126070
                r = state;
132
        }
133
134 3914922
        fptr = f; rptr = r;
135 3914922
        return ((long)i);
136
}
137
138
double
139 77
VRND_RandomTestableDouble(void)
140
{
141 77
        return (
142 77
                ldexp((double)VRND_RandomTestable(), -31) +
143 77
                ldexp((double)VRND_RandomTestable(), -62)
144
        );
145
}
146
147
int
148 186432
VRND_RandomCrypto(void *ptr, size_t len)
149
{
150
        int fd;
151
        char *p;
152
        ssize_t l;
153
154 186432
        AN(ptr);
155 186432
        fd = open("/dev/urandom", O_RDONLY);
156 186432
        if (fd < 0)
157 0
                return (-1);
158 433480
        for (p = ptr; len > 0; len--, p++) {
159 247048
                l = read(fd, p, 1);
160 247048
                if (l != 1)
161 0
                        break;
162
        }
163 186432
        closefd(&fd);
164 186432
        return (len == 0 ? 0 : -1);
165
}
166
167
void
168 1955
VRND_SeedAll(void)
169
{
170
        unsigned long seed;
171
172 1955
        AZ(VRND_RandomCrypto(&seed, sizeof seed));
173 1955
        srandom(seed);
174 1955
        AZ(VRND_RandomCrypto(&seed, sizeof seed));
175 1955
        VRND_SeedTestable(seed);
176 1955
        AZ(VRND_RandomCrypto(&seed, sizeof seed));
177 1955
        srand48(seed);
178 1955
}