VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/rand.cpp@ 8217

Last change on this file since 8217 was 8170, checked in by vboxsync, 17 years ago

Rebranding: replacing more innotek strings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.8 KB
Line 
1/* $Id: rand.cpp 8170 2008-04-18 17:52:25Z vboxsync $ */
2/** @file
3 * Incredibly Portable Runtime - Random Number
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/rand.h>
36#include <iprt/time.h>
37#include <iprt/asm.h>
38#include <iprt/err.h>
39#include <iprt/assert.h>
40#include <iprt/thread.h>
41#include "internal/rand.h"
42
43
44/*******************************************************************************
45* Global Variables *
46*******************************************************************************/
47/** Lazy init. */
48static volatile bool g_fInitialized = false;
49/** The context variable for the fallback path. */
50static uint32_t g_u32Ctx;
51
52
53/*******************************************************************************
54* Internal Functions *
55*******************************************************************************/
56static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx);
57
58
59/**
60 * Lazy initialization of the native and fallback random byte sources.
61 *
62 */
63static void rtRandLazyInit(void)
64{
65 /*
66 * Seed the fallback random code.
67 */
68 g_u32Ctx = (uint32_t)(ASMReadTSC() >> 8);
69
70 /*
71 * Call host specific init.
72 */
73 rtRandLazyInitNative();
74 g_fInitialized = true;
75}
76
77
78/**
79 * Internal wrapper for the native and generic random byte methods.
80 *
81 * @param pv Where to store the random bytes.
82 * @param cb Number of bytes to generate.
83 */
84static void rtRandGenBytes(void *pv, size_t cb)
85{
86 Assert(cb);
87 if (RT_UNLIKELY(!g_fInitialized))
88 rtRandLazyInit();
89
90 int rc = rtRandGenBytesNative(pv, cb);
91 if (RT_FAILURE(rc))
92 rtRandGenBytesFallback(pv, cb);
93}
94
95
96/**
97 * Fills a buffer with random bytes.
98 *
99 * @param pv Where to store the random bytes.
100 * @param cb Number of bytes to generate.
101 */
102RTDECL(void) RTRandBytes(void *pv, size_t cb)
103{
104 if (cb)
105 rtRandGenBytes(pv, cb);
106}
107
108
109/**
110 * Generate a 32-bit signed random number in the set [i32First..i32Last].
111 *
112 * @returns The random number.
113 * @param i32First First number in the set.
114 * @param i32Last Last number in the set.
115 */
116RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last)
117{
118 /* get 4 random bytes. */
119 union
120 {
121 uint32_t off;
122 uint8_t ab[4];
123 } u;
124 rtRandGenBytes(&u.ab, sizeof(u));
125
126
127 /* squeeze it into the requested range. */
128 uint32_t offLast = i32Last - i32First;
129 if (u.off > offLast)
130 {
131 do
132 {
133 u.off >>= 1;
134 } while (u.off > offLast);
135 }
136 return i32First + u.off;
137}
138
139
140/**
141 * Generate a 32-bit signed random number.
142 *
143 * @returns The random number.
144 */
145RTDECL(int32_t) RTRandS32(void)
146{
147 return RTRandS32Ex(INT32_MIN, INT32_MAX);
148}
149
150
151/**
152 * Generate a 32-bit unsigned random number in the set [u32First..u32Last].
153 *
154 * @returns The random number.
155 * @param u32First First number in the set.
156 * @param u32Last Last number in the set.
157 */
158RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last)
159{
160 /* get 4 random bytes. */
161 union
162 {
163 uint32_t off;
164 uint8_t ab[4];
165 } u;
166 rtRandGenBytes(&u.ab, sizeof(u));
167
168
169 /* squeeze it into the requested range. */
170 const uint32_t offLast = u32Last - u32First;
171 if (u.off > offLast)
172 {
173 do
174 {
175 u.off >>= 1;
176 } while (u.off > offLast);
177 }
178 return u32First + u.off;
179}
180
181
182/**
183 * Generate a 32-bit unsigned random number.
184 *
185 * @returns The random number.
186 */
187RTDECL(uint32_t) RTRandU32(void)
188{
189 return RTRandU32Ex(0, UINT32_MAX);
190}
191
192
193/**
194 * Generate a 64-bit signed random number in the set [i64First..i64Last].
195 *
196 * @returns The random number.
197 * @param i64First First number in the set.
198 * @param i64Last Last number in the set.
199 */
200RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last)
201{
202 /* get 8 random bytes. */
203 union
204 {
205 uint64_t off;
206 uint8_t ab[8];
207 } u;
208 rtRandGenBytes(&u.ab, sizeof(u));
209
210 /* squeeze it into the requested range. */
211 uint64_t offLast = i64Last - i64First;
212 if (u.off > offLast)
213 {
214 do
215 {
216 u.off >>= 1;
217 } while (u.off > offLast);
218 }
219 return i64First + u.off;
220}
221
222
223/**
224 * Generate a 64-bit signed random number.
225 *
226 * @returns The random number.
227 */
228RTDECL(int64_t) RTRandS64(void)
229{
230 return RTRandS64Ex(INT64_MIN, INT64_MAX);
231}
232
233
234/**
235 * Generate a 64-bit unsigned random number in the set [u64First..u64Last].
236 *
237 * @returns The random number.
238 * @param u64First First number in the set.
239 * @param u64Last Last number in the set.
240 */
241RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last)
242{
243 /* get 8 random bytes. */
244 union
245 {
246 uint64_t off;
247 uint8_t ab[8];
248 } u;
249 rtRandGenBytes(&u.ab, sizeof(u));
250
251 /* squeeze it into the requested range. */
252 const uint64_t offLast = u64Last - u64First;
253 if (u.off > offLast)
254 {
255 do
256 {
257 u.off >>= 1;
258 } while (u.off > offLast);
259 }
260 return u64First + u.off;
261}
262
263
264/**
265 * Generate a 64-bit unsigned random number.
266 *
267 * @returns The random number.
268 */
269RTDECL(uint64_t) RTRandU64(void)
270{
271 return RTRandU64Ex(0, UINT64_MAX);
272}
273
274
275/**
276 * Fallback random byte source.
277 *
278 * @param pv Where to store the random bytes.
279 * @param cb Number of bytes to generate.
280 */
281void rtRandGenBytesFallback(void *pv, size_t cb)
282{
283 uint8_t *pb = (uint8_t *)pv;
284 for (unsigned i = 0;; i++)
285 {
286 uint32_t u32 = rtRandGenBytesFallbackU31(&g_u32Ctx);
287
288 *pb++ = (uint8_t)u32;
289 if (!--cb)
290 break;
291
292 u32 >>= 8;
293 *pb++ = (uint8_t)u32;
294 if (!--cb)
295 break;
296
297 u32 >>= 8;
298 *pb++ = (uint8_t)u32;
299 if (!--cb)
300 break;
301
302 /* Is this really a good idea? */
303 if (!(i % 3))
304 {
305 if (i)
306 RTThreadYield();
307 *pb++ = (uint8_t)ASMReadTSC();
308 if (!--cb)
309 break;
310 }
311 }
312
313}
314
315
316/*-
317 * Copyright (c) 1990, 1993
318 * The Regents of the University of California. All rights reserved.
319 *
320 * Redistribution and use in source and binary forms, with or without
321 * modification, are permitted provided that the following conditions
322 * are met:
323 * 1. Redistributions of source code must retain the above copyright
324 * notice, this list of conditions and the following disclaimer.
325 * 2. Redistributions in binary form must reproduce the above copyright
326 * notice, this list of conditions and the following disclaimer in the
327 * documentation and/or other materials provided with the distribution.
328 * 4. Neither the name of the University nor the names of its contributors
329 * may be used to endorse or promote products derived from this software
330 * without specific prior written permission.
331 *
332 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
333 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
334 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
335 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
336 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
337 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
338 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
339 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
340 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
342 * SUCH DAMAGE.
343 */
344
345/* The core of:
346__FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/rand.c,v 1.16 2007/01/09 00:28:10 imp Exp $");
347*/
348
349/**
350 * Generates an unsigned 31 bit pseudo random number.
351 *
352 * @returns pseudo random number.
353 * @param pCtx The context.
354 */
355static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx)
356{
357 /*
358 * Compute x = (7^5 * x) mod (2^31 - 1)
359 * without overflowing 31 bits:
360 * (2^31 - 1) = 127773 * (7^5) + 2836
361 *
362 * From "Random number generators: good ones are hard to find", Park and
363 * Miller, Communications of the ACM, vol. 31, no. 10, October 1988, p. 1195.
364 */
365 uint32_t Ctx = *pCtx;
366 if (!Ctx) /* must not be zero. */
367 Ctx = 0x20070212;
368 uint32_t Hi = Ctx / 127773;
369 uint32_t Lo = Ctx % 127773;
370 int32_t x = 16807 * Lo - 2836 * Hi;
371 if (x < 0)
372 x += INT32_MAX;
373 *pCtx = x;
374 return x % INT32_MAX;
375}
376
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette