Changeset 11523 in vbox for trunk/src/VBox/Runtime/common/rand/rand.cpp
- Timestamp:
- Aug 20, 2008 8:48:52 PM (17 years ago)
- svn:sync-xref-src-repo-rev:
- 35074
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/rand/rand.cpp
r11172 r11523 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Random Number 3 * IPRT - Random Numbers. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-200 7Sun Microsystems, Inc.7 * Copyright (C) 2006-2008 Sun Microsystems, Inc. 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 39 39 #include <iprt/assert.h> 40 40 #include <iprt/thread.h> 41 #include <iprt/once.h> 41 42 #include "internal/rand.h" 42 43 … … 45 46 * Global Variables * 46 47 *******************************************************************************/ 47 /** Lazy init. */ 48 static volatile bool g_fInitialized = false; 49 /** The context variable for the fallback path. */ 50 static uint32_t g_u32Ctx; 51 52 53 /******************************************************************************* 54 * Internal Functions * 55 *******************************************************************************/ 56 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx); 48 /** For lazily initializating of the random generator. */ 49 static RTONCE g_rtRandOnce = RTONCE_INITIALIZER; 50 /** The default random generator. */ 51 static RTRAND g_hRand = NIL_RTRAND; 57 52 58 53 59 54 /** 60 * Lazy initialization of the native and fallback random byte sources.55 * Perform lazy initialization. 61 56 * 57 * @returns IPRT status code. 58 * @param pvUser1 Ignored. 59 * @param pvUser2 Ignored. 62 60 */ 63 static void rtRandLazyInit(void)61 static DECLCALLBACK(int) rtRandInitOnce(void *pvUser1, void *pvUser2) 64 62 { 65 /* 66 * Seed the fallback random code. 67 */ 68 g_u32Ctx = (uint32_t)(ASMReadTSC() >> 8); 63 NOREF(pvUser1); 64 NOREF(pvUser2); 69 65 70 /* 71 * Call host specific init. 72 */ 73 rtRandLazyInitNative(); 74 g_fInitialized = true; 66 RTRAND hRand; 67 int rc = RTRandAdvCreateNonPseudo(&hRand); 68 if (RT_FAILURE(rc)) 69 rc = RTRandAdvCreateParkMiller(&hRand); 70 if (RT_SUCCESS(rc)) 71 { 72 RTRandAdvSeed(hRand, ASMReadTSC() >> 8); 73 g_hRand = hRand; 74 } 75 else 76 AssertRC(rc); 77 78 return rc; 75 79 } 76 80 77 81 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 */ 84 static void rtRandGenBytes(void *pv, size_t cb) 82 RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW 85 83 { 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); 84 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 85 RTRandAdvBytes(g_hRand, pv, cb); 93 86 } 94 87 95 88 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 */ 102 RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW 89 RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW 103 90 { 104 if (cb)105 rtRandGenBytes(pv, cb);91 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 92 return RTRandAdvU32Ex(g_hRand, u32First, u32Last); 106 93 } 107 94 108 95 109 /** 110 * Generate a 32-bit unsigned random number in the set [u32First..u32Last]. 111 * 112 * @returns The random number. 113 * @param u32First First number in the set. 114 * @param u32Last Last number in the set. 115 */ 116 RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW 96 RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW 117 97 { 118 union 119 { 120 uint32_t off; 121 uint8_t ab[5]; 122 } u; 123 124 const uint32_t offLast = u32Last - u32First; 125 if (offLast == UINT32_MAX) 126 /* get 4 random bytes and return them raw. */ 127 rtRandGenBytes(&u.ab[0], sizeof(u.off)); 128 else if (!(offLast & UINT32_C(0xf0000000))) 129 { 130 /* get 4 random bytes and do simple squeeze. */ 131 rtRandGenBytes(&u.ab[0], sizeof(u.off)); 132 u.off %= offLast + 1; 133 u.off += u32First; 134 } 135 else 136 { 137 /* get 5 random bytes and do shifted squeeze. (this ain't perfect) */ 138 rtRandGenBytes(&u.ab[0], sizeof(u.ab)); 139 u.off %= (offLast >> 4) + 1; 140 u.off <<= 4; 141 u.off |= u.ab[4] & 0xf; 142 if (u.off > offLast) 143 u.off = offLast; 144 u.off += u32First; 145 } 146 return u.off; 98 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 99 return RTRandAdvU32(g_hRand); 147 100 } 148 101 149 102 150 /** 151 * Generate a 32-bit unsigned random number. 152 * 153 * @returns The random number. 154 */ 155 RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW 103 RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW 156 104 { 157 return RTRandU32Ex(0, UINT32_MAX); 105 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 106 return RTRandAdvS32Ex(g_hRand, i32First, i32Last); 158 107 } 159 108 160 109 161 /** 162 * Generate a 32-bit signed random number in the set [i32First..i32Last]. 163 * 164 * @returns The random number. 165 * @param i32First First number in the set. 166 * @param i32Last Last number in the set. 167 */ 168 RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW 110 RTDECL(int32_t) RTRandS32(void) RT_NO_THROW 169 111 { 170 if (i32First == INT32_MIN && i32Last == INT32_MAX) 171 return (int32_t)RTRandU32Ex(0, UINT32_MAX); 172 return RTRandU32Ex(0, i32Last - i32First) + i32First; 112 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 113 return RTRandAdvS32(g_hRand); 173 114 } 174 115 175 116 176 /** 177 * Generate a 32-bit signed random number. 178 * 179 * @returns The random number. 180 */ 181 RTDECL(int32_t) RTRandS32(void) RT_NO_THROW 117 RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW 182 118 { 183 return (int32_t)RTRandU32Ex(0, UINT32_MAX); 119 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 120 return RTRandAdvU64Ex(g_hRand, u64First, u64Last); 184 121 } 185 122 186 123 187 /** 188 * Generate a 64-bit unsigned random number in the set [u64First..u64Last]. 189 * 190 * @returns The random number. 191 * @param u64First First number in the set. 192 * @param u64Last Last number in the set. 193 */ 194 RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW 124 RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW 195 125 { 196 union 197 { 198 uint64_t off; 199 uint32_t off32; 200 uint8_t ab[9]; 201 } u; 202 203 const uint64_t offLast = u64Last - u64First; 204 if (offLast == UINT64_MAX) 205 /* get 8 random bytes and return them raw. */ 206 rtRandGenBytes(&u.ab[0], sizeof(u.off)); 207 else if (!(offLast & UINT64_C(0xf000000000000000))) 208 { 209 /* get 8 random bytes and do simple squeeze. */ 210 rtRandGenBytes(&u.ab[0], sizeof(u.off)); 211 u.off %= offLast + 1; 212 u.off += u64First; 213 } 214 else 215 { 216 /* get 9 random bytes and do shifted squeeze. (this ain't perfect) */ 217 rtRandGenBytes(&u.ab[0], sizeof(u.ab)); 218 u.off %= (offLast >> 4) + 1; 219 u.off <<= 4; 220 u.off |= u.ab[8] & 0xf; 221 if (u.off > offLast) 222 u.off = offLast; 223 u.off += u64First; 224 } 225 return u.off; 126 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 127 return RTRandAdvU64(g_hRand); 226 128 } 227 129 228 130 229 /** 230 * Generate a 64-bit unsigned random number. 231 * 232 * @returns The random number. 233 */ 234 RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW 131 RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW 235 132 { 236 return RTRandU64Ex(0, UINT64_MAX); 133 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 134 return RTRandAdvS64Ex(g_hRand, i64First, i64Last); 237 135 } 238 136 239 137 240 /** 241 * Generate a 64-bit signed random number in the set [i64First..i64Last]. 242 * 243 * @returns The random number. 244 * @param i64First First number in the set. 245 * @param i64Last Last number in the set. 246 */ 247 RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW 138 RTDECL(int64_t) RTRandS64(void) RT_NO_THROW 248 139 { 249 if (i64First == INT64_MIN && i64Last == INT64_MAX) 250 return (int64_t)RTRandU64Ex(0, UINT64_MAX); 251 return (int64_t)RTRandU64Ex(0, i64Last - i64First) + i64First; 140 RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL); 141 return RTRandAdvS32(g_hRand); 252 142 } 253 143 254 255 /**256 * Generate a 64-bit signed random number.257 *258 * @returns The random number.259 */260 RTDECL(int64_t) RTRandS64(void) RT_NO_THROW261 {262 return (int64_t)RTRandU64Ex(0, UINT64_MAX);263 }264 265 266 /**267 * Fallback random byte source.268 *269 * @param pv Where to store the random bytes.270 * @param cb Number of bytes to generate.271 */272 void rtRandGenBytesFallback(void *pv, size_t cb) RT_NO_THROW273 {274 uint64_t u64Last = 0;275 uint8_t *pb = (uint8_t *)pv;276 for (unsigned i = 0;; i++)277 {278 uint32_t u32 = rtRandGenBytesFallbackU31(&g_u32Ctx);279 280 *pb++ = (uint8_t)u32;281 if (!--cb)282 break;283 284 u32 >>= 8;285 *pb++ = (uint8_t)u32;286 if (!--cb)287 break;288 289 u32 >>= 8;290 *pb++ = (uint8_t)u32;291 if (!--cb)292 break;293 294 /*295 * Is this really a good idea? Looks like we cannot296 * quite trust the lower bits here for instance...297 */298 if (!(i % 3))299 {300 uint64_t u64 = ASMReadTSC();301 uint64_t u64Delta = u64 - u64Last;302 if (u64Delta > 0xff)303 {304 u32 >>= 8;305 *pb++ = ((uint8_t)u64 >> 5) | (u32 << 3);306 if (!--cb)307 break;308 u64Last = u64;309 }310 }311 }312 }313 314 315 /*-316 * Copyright (c) 1990, 1993317 * The Regents of the University of California. All rights reserved.318 *319 * Redistribution and use in source and binary forms, with or without320 * modification, are permitted provided that the following conditions321 * are met:322 * 1. Redistributions of source code must retain the above copyright323 * notice, this list of conditions and the following disclaimer.324 * 2. Redistributions in binary form must reproduce the above copyright325 * notice, this list of conditions and the following disclaimer in the326 * documentation and/or other materials provided with the distribution.327 * 4. Neither the name of the University nor the names of its contributors328 * may be used to endorse or promote products derived from this software329 * without specific prior written permission.330 *331 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND332 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE333 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE334 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE335 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL336 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS337 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)338 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT339 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY340 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF341 * SUCH DAMAGE.342 */343 344 /* The core of:345 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/rand.c,v 1.16 2007/01/09 00:28:10 imp Exp $");346 */347 348 /**349 * Generates an unsigned 31 bit pseudo random number.350 *351 * @returns pseudo random number.352 * @param pCtx The context.353 */354 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx)355 {356 /*357 * Compute x = (7^5 * x) mod (2^31 - 1)358 * without overflowing 31 bits:359 * (2^31 - 1) = 127773 * (7^5) + 2836360 *361 * From "Random number generators: good ones are hard to find", Park and362 * Miller, Communications of the ACM, vol. 31, no. 10, October 1988, p. 1195.363 */364 uint32_t Ctx = *pCtx;365 if (!Ctx) /* must not be zero. */366 Ctx = 0x20070212;367 uint32_t Hi = Ctx / 127773;368 uint32_t Lo = Ctx % 127773;369 int32_t x = 16807 * Lo - 2836 * Hi;370 if (x < 0)371 x += INT32_MAX;372 *pCtx = x;373 return x % INT32_MAX;374 }375
Note:
See TracChangeset
for help on using the changeset viewer.