mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-23 02:50:29 +00:00
Make numerous improvements
- Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
This commit is contained in:
parent
fa7b4f5bd1
commit
39bf41f4eb
806 changed files with 77494 additions and 63859 deletions
|
@ -48,13 +48,9 @@ static bool have_getrandom;
|
|||
* - RtlGenRandom() on Windows
|
||||
* - getentropy() on XNU and OpenBSD
|
||||
* - sysctl(KERN_ARND) on FreeBSD and NetBSD
|
||||
* - RDSEED on Broadwell+ and Xen+ unless GRND_NORDRND
|
||||
* - RDRAND on Ivybridge+ and Xen+ unless GRND_NORDRND
|
||||
*
|
||||
* The following flags may be specified:
|
||||
*
|
||||
* - GRND_NORDRND: Don't source rando from hardware.
|
||||
* - GRND_NOSYSTEM: Don't source rando from operating system.
|
||||
* - GRND_RANDOM: Halt the entire system while I tap an entropy pool
|
||||
* so small that it's hard to use statistics to test if it's random
|
||||
* - GRND_NONBLOCK: Do not wait for i/o events or me to jiggle my
|
||||
|
@ -75,137 +71,44 @@ ssize_t getrandom(void *p, size_t n, unsigned f) {
|
|||
int fd, cmd[2];
|
||||
sigset_t neu, old;
|
||||
if (n > 256) n = 256;
|
||||
if (!IsTiny() &&
|
||||
((f & ~(GRND_RANDOM | GRND_NONBLOCK | GRND_NORDRND | GRND_NOSYSTEM)) ||
|
||||
(f & (GRND_NORDRND | GRND_NOSYSTEM)) ==
|
||||
(GRND_NORDRND | GRND_NOSYSTEM))) {
|
||||
return einval();
|
||||
}
|
||||
if (!(f & GRND_NOSYSTEM)) {
|
||||
if (IsWindows()) {
|
||||
if (RtlGenRandom(p, n)) {
|
||||
rc = n;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
} else if (IsFreebsd() || IsNetbsd()) {
|
||||
if (IsFreebsd()) {
|
||||
cmd[0] = 1; /* CTL_KERN */
|
||||
cmd[1] = 37; /* KERN_ARND */
|
||||
} else {
|
||||
cmd[0] = 1; /* CTL_KERN */
|
||||
cmd[1] = 81; /* KERN_ARND */
|
||||
}
|
||||
m = n;
|
||||
if ((rc = sysctl(cmd, 2, p, &m, 0, 0)) != -1) {
|
||||
rc = m;
|
||||
}
|
||||
} else if (have_getrandom) {
|
||||
if ((rc = sys_getrandom(p, n, f & (GRND_RANDOM | GRND_NONBLOCK))) != -1) {
|
||||
if (!rc && (IsXnu() || IsOpenbsd())) {
|
||||
rc = n;
|
||||
}
|
||||
}
|
||||
} else if ((fd = __sys_openat(
|
||||
AT_FDCWD,
|
||||
(f & GRND_RANDOM) ? "/dev/random" : "/dev/urandom",
|
||||
O_RDONLY | ((f & GRND_NONBLOCK) ? O_NONBLOCK : 0), 0)) !=
|
||||
-1) {
|
||||
rc = sys_read(fd, p, n);
|
||||
sys_close(fd);
|
||||
if ((f & ~(GRND_RANDOM | GRND_NONBLOCK))) return einval();
|
||||
if (IsWindows()) {
|
||||
if (RtlGenRandom(p, n)) {
|
||||
rc = n;
|
||||
} else {
|
||||
return enosys();
|
||||
return __winerr();
|
||||
}
|
||||
} else if (IsFreebsd() || IsNetbsd()) {
|
||||
if (IsFreebsd()) {
|
||||
cmd[0] = 1; /* CTL_KERN */
|
||||
cmd[1] = 37; /* KERN_ARND */
|
||||
} else {
|
||||
cmd[0] = 1; /* CTL_KERN */
|
||||
cmd[1] = 81; /* KERN_ARND */
|
||||
}
|
||||
m = n;
|
||||
if ((rc = sysctl(cmd, 2, p, &m, 0, 0)) != -1) {
|
||||
rc = m;
|
||||
}
|
||||
} else if (have_getrandom) {
|
||||
if ((rc = sys_getrandom(p, n, f & (GRND_RANDOM | GRND_NONBLOCK))) != -1) {
|
||||
if (!rc && (IsXnu() || IsOpenbsd())) {
|
||||
rc = n;
|
||||
}
|
||||
}
|
||||
} else if ((fd = __sys_openat(
|
||||
AT_FDCWD, (f & GRND_RANDOM) ? "/dev/random" : "/dev/urandom",
|
||||
O_RDONLY | ((f & GRND_NONBLOCK) ? O_NONBLOCK : 0), 0)) !=
|
||||
-1) {
|
||||
rc = sys_read(fd, p, n);
|
||||
sys_close(fd);
|
||||
} else {
|
||||
memset(p, 0, n);
|
||||
rc = n;
|
||||
}
|
||||
if (rc != -1) {
|
||||
if (!IsTiny()) {
|
||||
if (rc < 0 || rc > n) {
|
||||
abort();
|
||||
}
|
||||
if (f & (GRND_RANDOM | GRND_NONBLOCK)) {
|
||||
if (n && !rc) {
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
if (rc != n) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(f & GRND_NORDRND)) {
|
||||
if (X86_HAVE(RDSEED)) {
|
||||
for (i = j = 0; i < rc; ++j) {
|
||||
/* CF=1: Destination register valid. Quoth Intel DRNG-SIG 4.1.3 */
|
||||
asm volatile(CFLAG_ASM("rdseed\t%1")
|
||||
: CFLAG_CONSTRAINT(cf), "=r"(x)
|
||||
: /* no inputs */
|
||||
: "cc");
|
||||
if (cf) {
|
||||
j = 0;
|
||||
if (i + 8 <= rc) {
|
||||
x ^= READ64LE((char *)p + i);
|
||||
WRITE64LE((char *)p + i, x);
|
||||
i += 8;
|
||||
} else {
|
||||
for (; i < rc; x >>= 8) {
|
||||
((char *)p)[i++] ^= x;
|
||||
}
|
||||
}
|
||||
} else if (j == 10) {
|
||||
asm volatile("pause");
|
||||
}
|
||||
}
|
||||
rc = i;
|
||||
} else if (X86_HAVE(RDRND)) {
|
||||
for (i = j = 0; i < rc; ++j) {
|
||||
/* CF=1: Destination register valid. Quoth Intel DRNG-SIG 4.1.3 */
|
||||
asm volatile(CFLAG_ASM("rdrand\t%1")
|
||||
: CFLAG_CONSTRAINT(cf), "=r"(x)
|
||||
: /* no inputs */
|
||||
: "cc");
|
||||
if (cf) {
|
||||
j = 0;
|
||||
if (i + 8 <= rc) {
|
||||
x ^= READ64LE((char *)p + i);
|
||||
WRITE64LE((char *)p + i, x);
|
||||
i += 8;
|
||||
} else {
|
||||
for (; i < rc; x >>= 8) {
|
||||
((char *)p)[i++] ^= x;
|
||||
}
|
||||
}
|
||||
} else if (j == 10) {
|
||||
asm volatile("pause");
|
||||
}
|
||||
}
|
||||
rc = i;
|
||||
} else if (f & GRND_NOSYSTEM) {
|
||||
return enosys();
|
||||
}
|
||||
}
|
||||
return enosys();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static textstartup void getrandom_init(int argc, char **argv, char **envp,
|
||||
intptr_t *auxv) {
|
||||
extern unsigned kMutableCpuids[KCPUIDS_LEN][4] asm("kCpuids");
|
||||
/*
|
||||
* Clear RDRAND on AMD models before Zen and then some
|
||||
* since it's not only slow but can freeze after sleep
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=1150286
|
||||
*/
|
||||
if ((X86_HAVE(RDRND) || X86_HAVE(RDSEED)) &&
|
||||
(IsAuthenticAMD() &&
|
||||
(kX86CpuFamily < 0x17 ||
|
||||
(kX86CpuFamily == 0x17 &&
|
||||
(0x70 <= kX86CpuModel && kX86CpuModel <= 0x7F))))) {
|
||||
kMutableCpuids[KCPUIDS_1H][KCPUIDS_ECX] &= ~(1u << 30);
|
||||
kMutableCpuids[KCPUIDS_7H][KCPUIDS_EBX] &= ~(1u << 18);
|
||||
}
|
||||
static textstartup void getrandom_init(void) {
|
||||
if (sys_getrandom(0, 0, 0) == 0) {
|
||||
have_getrandom = true;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns number between 0 and 8.
|
||||
* Returns Shannon entropy of array.
|
||||
*
|
||||
* This gives you an idea of the density of information. Cryptographic
|
||||
* random should be in the ballpark of 7.9 whereas plaintext will be
|
||||
|
@ -29,6 +29,7 @@
|
|||
*
|
||||
* @param p is treated as binary octets
|
||||
* @param n should be at least 1000
|
||||
* @return number between 0 and 8
|
||||
*/
|
||||
double MeasureEntropy(const char *p, size_t n) {
|
||||
size_t i;
|
||||
|
@ -36,7 +37,7 @@ double MeasureEntropy(const char *p, size_t n) {
|
|||
long h[256];
|
||||
e = 0;
|
||||
if (n) {
|
||||
memset(h, 0, sizeof(h));
|
||||
bzero(h, sizeof(h));
|
||||
for (i = 0; i < n; ++i) {
|
||||
++h[p[i] & 255];
|
||||
}
|
||||
|
|
146
libc/rand/mt19937.c
Normal file
146
libc/rand/mt19937.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ │
|
||||
│ Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, │
|
||||
│ All rights reserved. │
|
||||
│ │
|
||||
│ Redistribution and use in source and binary forms, with or without │
|
||||
│ modification, are permitted provided that the following conditions │
|
||||
│ are met: │
|
||||
│ │
|
||||
│ 1. Redistributions of source code must retain the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer. │
|
||||
│ │
|
||||
│ 2. Redistributions in binary form must reproduce the above │
|
||||
│ copyright notice, this list of conditions and the following │
|
||||
│ disclaimer in the documentation and/or other materials │
|
||||
│ provided with the distribution. │
|
||||
│ │
|
||||
│ 3. The names of its contributors may not be used to endorse or │
|
||||
│ promote products derived from this software without specific │
|
||||
│ prior written permission. │
|
||||
│ │
|
||||
│ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS │
|
||||
│ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT │
|
||||
│ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR │
|
||||
│ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT │
|
||||
│ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, │
|
||||
│ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT │
|
||||
│ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, │
|
||||
│ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY │
|
||||
│ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT │
|
||||
│ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE │
|
||||
│ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. │
|
||||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
mt19937 (BSD-3)\\n\
|
||||
Copyright 1997-2004 Makoto Matsumoto and Takuji Nishimura\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/*
|
||||
* A C-program for MT19937-64 (2004/9/29 version).
|
||||
* Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
*
|
||||
* This is a 64-bit version of Mersenne Twister pseudorandom number
|
||||
* generator.
|
||||
*
|
||||
* Before using, initialize the state by using init_genrand64(seed)
|
||||
* or init_by_array64(init_key, key_length).
|
||||
*
|
||||
* References:
|
||||
* T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
|
||||
* ACM Transactions on Modeling and
|
||||
* Computer Simulation 10. (2000) 348--357.
|
||||
* M. Matsumoto and T. Nishimura,
|
||||
* ``Mersenne Twister: a 623-dimensionally equidistributed
|
||||
* uniform pseudorandom number generator''
|
||||
* ACM Transactions on Modeling and
|
||||
* Computer Simulation 8. (Jan. 1998) 3--30.
|
||||
*
|
||||
* Any feedback is very welcome.
|
||||
* http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
* email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
|
||||
*/
|
||||
|
||||
#define NN 312
|
||||
#define MM 156
|
||||
#define LM 0x7fffffff
|
||||
#define UM 0xffffffff80000000
|
||||
|
||||
static int mti = NN + 1;
|
||||
static uint64_t mt[NN];
|
||||
static const uint64_t mag01[2] = {0, 0xb5026f5aa96619e9};
|
||||
|
||||
/**
|
||||
* Initializes mt[NN] with small seed value.
|
||||
*
|
||||
* @see mt19937(), Smt19937()
|
||||
*/
|
||||
void _smt19937(uint64_t seed) {
|
||||
mt[0] = seed;
|
||||
for (mti = 1; mti < NN; mti++) {
|
||||
mt[mti] = 0x5851f42d4c957f2d * (mt[mti - 1] ^ (mt[mti - 1] >> 62)) + mti;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes mt[NN] with array.
|
||||
*
|
||||
* @param K is the array for initializing keys
|
||||
* @param n is its length
|
||||
* @see mt19937(), smt19937()
|
||||
*/
|
||||
void _Smt19937(uint64_t K[], size_t n) {
|
||||
size_t i, j, k;
|
||||
_smt19937(19650218);
|
||||
for (i = 1, j = 0, k = MAX(NN, n); k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 62)) * 0x369dea0f31a53f85)) +
|
||||
K[j] + j;
|
||||
if (++i >= NN) mt[0] = mt[NN - 1], i = 1;
|
||||
if (++j >= n) j = 0;
|
||||
}
|
||||
for (k = NN - 1; k; k--) {
|
||||
mt[i] =
|
||||
(mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 62)) * 0x27bb2ee687b0b0fd)) - i;
|
||||
if (++i >= NN) mt[0] = mt[NN - 1], i = 1;
|
||||
}
|
||||
mt[0] = 0x8000000000000000; /* assures non-zero initial array */
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random integer on [0, 2^64)-interval.
|
||||
*
|
||||
* This uses the Mersenne Twister pseudorandom number generator.
|
||||
*
|
||||
* @see smt19937(), Smt19937()
|
||||
*/
|
||||
uint64_t _mt19937(void) {
|
||||
int i;
|
||||
uint64_t x;
|
||||
if (mti >= NN) {
|
||||
if (mti == NN + 1) _smt19937(5489);
|
||||
for (i = 0; i < NN - MM; i++) {
|
||||
x = (mt[i] & UM) | (mt[i + 1] & LM);
|
||||
mt[i] = mt[i + MM] ^ (x >> 1) ^ mag01[x & 1];
|
||||
}
|
||||
for (; i < NN - 1; i++) {
|
||||
x = (mt[i] & UM) | (mt[i + 1] & LM);
|
||||
mt[i] = mt[i + (MM - NN)] ^ (x >> 1) ^ mag01[x & 1];
|
||||
}
|
||||
x = (mt[NN - 1] & UM) | (mt[0] & LM);
|
||||
mt[NN - 1] = mt[MM - 1] ^ (x >> 1) ^ mag01[x & 1];
|
||||
mti = 0;
|
||||
}
|
||||
x = mt[mti++];
|
||||
x ^= (x >> 29) & 0x5555555555555555;
|
||||
x ^= (x << 17) & 0x71d67fffeda60000;
|
||||
x ^= (x << 37) & 0xfff7eee000000000;
|
||||
x ^= (x >> 43);
|
||||
return x;
|
||||
}
|
|
@ -1,32 +1,42 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RAND_RAND_H_
|
||||
#define COSMOPOLITAN_LIBC_RAND_RAND_H_
|
||||
#define RAND_MAX __INT_MAX__
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § random ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define RAND_MAX __INT_MAX__
|
||||
void srand(uint64_t) nothrow nocallback;
|
||||
int rand(void) nothrow nocallback;
|
||||
uint64_t rand64(void) nothrow nocallback;
|
||||
int rand(void);
|
||||
void srand(uint64_t);
|
||||
double poz(double);
|
||||
double pochisq(double, int);
|
||||
void rt_init(int);
|
||||
void rt_add(void *, int);
|
||||
void rt_end(double *, double *, double *, double *, double *);
|
||||
void *rngset(void *, size_t, uint64_t (*)(void), size_t) paramsnonnull();
|
||||
char *strfry(char *);
|
||||
int getentropy(void *, size_t);
|
||||
ssize_t getrandom(void *, size_t, unsigned);
|
||||
uint64_t rdrand(void);
|
||||
uint64_t rdseed(void);
|
||||
float randf(void);
|
||||
char *initstate(unsigned, char *, size_t);
|
||||
char *setstate(char *);
|
||||
long random(void);
|
||||
void srandom(unsigned);
|
||||
|
||||
uint64_t vigna(void);
|
||||
uint64_t vigna_r(uint64_t[hasatleast 1]);
|
||||
void svigna(uint64_t);
|
||||
uint64_t rdrand(void);
|
||||
uint64_t rdseed(void);
|
||||
uint64_t rand64(void);
|
||||
void _smt19937(uint64_t);
|
||||
void _Smt19937(uint64_t[], size_t);
|
||||
uint64_t _mt19937(void);
|
||||
double _real1(uint64_t);
|
||||
double _real2(uint64_t);
|
||||
double _real3(uint64_t);
|
||||
double MeasureEntropy(const char *, size_t);
|
||||
void *rngset(void *, size_t, uint64_t (*)(void), size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -45,6 +45,10 @@ $(LIBC_RAND_A).pkg: \
|
|||
$(LIBC_RAND_A_OBJS) \
|
||||
$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/libc/rand/mt19937-64.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-ffunction-sections
|
||||
|
||||
LIBC_RAND_LIBS = $(foreach x,$(LIBC_RAND_ARTIFACTS),$($(x)))
|
||||
LIBC_RAND_SRCS = $(foreach x,$(LIBC_RAND_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_RAND_HDRS = $(foreach x,$(LIBC_RAND_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/xadd.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
@ -28,46 +30,45 @@ static uint64_t thepool;
|
|||
/**
|
||||
* Returns nondeterministic random data.
|
||||
*
|
||||
* This random number seed generator blends information from:
|
||||
* This function automatically seeds itself on startup and reseeds
|
||||
* itself after fork() and vfork(). It takes about nanosecond to run.
|
||||
* That makes it much slower than vigna() and rand() but much faster
|
||||
* than rdrand() and rdseed().
|
||||
*
|
||||
* - rdtsc() hardware clock
|
||||
* - getpid() process identifier
|
||||
* - getauxval(AT_RANDOM) on Linux
|
||||
*
|
||||
* It's 100% guaranteed to not hard block the system.
|
||||
*
|
||||
* @see rngset(), getrandom()
|
||||
* @see rdseed(), rdrand(), rand(), random(), rngset()
|
||||
* @note based on vigna's algorithm
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
uint64_t rand64(void) {
|
||||
bool cf;
|
||||
register uint64_t t;
|
||||
t = thepool;
|
||||
t ^= getpid() * 11400714819643198487ull + 123456789123456789;
|
||||
t ^= t << 13;
|
||||
t ^= t >> 7;
|
||||
t ^= t << 17;
|
||||
t ^= rdtsc() * 11400714819643198487ull + 123456789123456789;
|
||||
t ^= t << 13;
|
||||
t ^= t >> 7;
|
||||
t ^= t << 17;
|
||||
thepool ^= t;
|
||||
return t;
|
||||
if (X86_HAVE(RDSEED)) {
|
||||
asm volatile(CFLAG_ASM("rdseed\t%1")
|
||||
: CFLAG_CONSTRAINT(cf), "=r"(t)
|
||||
: /* no inputs */
|
||||
: "cc");
|
||||
if (cf) {
|
||||
thepool ^= t;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
t = _xadd(&thepool, 0x9e3779b97f4a7c15);
|
||||
t ^= (getpid() * 0x1001111111110001ull + 0xdeaadead) >> 31;
|
||||
t = (t ^ (t >> 30)) * 0xbf58476d1ce4e5b9;
|
||||
t = (t ^ (t >> 27)) * 0x94d049bb133111eb;
|
||||
return t ^ (t >> 31);
|
||||
}
|
||||
|
||||
static textstartup void rand64_init(int argc, char **argv, char **envp,
|
||||
intptr_t *auxv) {
|
||||
uint64_t t;
|
||||
t = kStartTsc * 88172645463325252 + 123456789123456789;
|
||||
if (AT_RANDOM) {
|
||||
for (; auxv[0]; auxv += 2) {
|
||||
if (auxv[0] == AT_RANDOM) {
|
||||
t ^= READ64LE((const char *)auxv[1]);
|
||||
break;
|
||||
}
|
||||
for (; auxv[0]; auxv += 2) {
|
||||
if (auxv[0] == AT_RANDOM) {
|
||||
thepool = READ64LE((const char *)auxv[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
thepool = t;
|
||||
thepool = kStartTsc;
|
||||
}
|
||||
|
||||
const void *const g_rand64_init[] initarray = {rand64_init};
|
||||
|
|
|
@ -16,8 +16,62 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/sysv/consts/grnd.h"
|
||||
|
||||
uint64_t rdrand(void) {
|
||||
return rand64();
|
||||
STATIC_YOINK("rdrand_init");
|
||||
|
||||
static noinline uint64_t rdrand_failover(void) {
|
||||
int f;
|
||||
size_t i;
|
||||
ssize_t r;
|
||||
volatile uint64_t b;
|
||||
register uint64_t x;
|
||||
for (f = GRND_RANDOM | GRND_NONBLOCK, i = 0; i < 8; i += r) {
|
||||
if ((r = getrandom((char *)&b + i, 8 - i, f)) <= 0) {
|
||||
if (r == -1 && errno == EINTR) {
|
||||
r = 0;
|
||||
} else if (r == -1 && errno == EAGAIN) {
|
||||
f = 0;
|
||||
} else {
|
||||
return rand64();
|
||||
}
|
||||
}
|
||||
}
|
||||
x = b;
|
||||
b = 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves 64-bits of hardware random data from RDRAND instruction.
|
||||
*
|
||||
* If RDRAND isn't available (we check CPUID and we also disable it
|
||||
* automatically for microarchitectures where it's slow or buggy) then
|
||||
* we try getrandom(), RtlGenRandom(), or sysctl(KERN_ARND). If those
|
||||
* aren't available then we try /dev/urandom and if that fails, we try
|
||||
* getauxval(AT_RANDOM), and if not we finally use RDTSC and getpid().
|
||||
*
|
||||
* This function takes between 10 nanoseconds to several microseconds.
|
||||
*
|
||||
* @see rngset(), rdseed(), rand64()
|
||||
*/
|
||||
uint64_t rdrand(void) {
|
||||
int i;
|
||||
char cf;
|
||||
uint64_t x;
|
||||
if (X86_HAVE(RDRND)) {
|
||||
for (i = 0; i < 10; ++i) {
|
||||
asm volatile(CFLAG_ASM("rdrand\t%1")
|
||||
: CFLAG_CONSTRAINT(cf), "=r"(x)
|
||||
: /* no inputs */
|
||||
: "cc");
|
||||
if (cf) return x;
|
||||
asm volatile("pause");
|
||||
}
|
||||
}
|
||||
return rdrand_failover();
|
||||
}
|
||||
|
|
43
libc/rand/rdrand_init.c
Normal file
43
libc/rand/rdrand_init.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/kcpuids.h"
|
||||
#include "libc/nexgen32e/vendor.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/nexgen32e/x86info.h"
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
textstartup void rdrand_init(int argc, char **argv, char **envp,
|
||||
intptr_t *auxv) {
|
||||
extern unsigned kMutableCpuids[KCPUIDS_LEN][4] asm("kCpuids");
|
||||
/*
|
||||
* Clear RDRAND on AMD models before Zen and then some
|
||||
* since it's not only slow but can freeze after sleep
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=1150286
|
||||
*/
|
||||
if ((X86_HAVE(RDRND) || X86_HAVE(RDSEED)) &&
|
||||
(IsAuthenticAMD() &&
|
||||
(kX86CpuFamily < 0x17 ||
|
||||
(kX86CpuFamily == 0x17 &&
|
||||
(0x70 <= kX86CpuModel && kX86CpuModel <= 0x7F))))) {
|
||||
kMutableCpuids[KCPUIDS_1H][KCPUIDS_ECX] &= ~(1u << 30);
|
||||
kMutableCpuids[KCPUIDS_7H][KCPUIDS_EBX] &= ~(1u << 18);
|
||||
}
|
||||
}
|
||||
|
||||
const void *const g_rdrand_init[] initarray = {rdrand_init};
|
|
@ -16,17 +16,38 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/grnd.h"
|
||||
|
||||
/**
|
||||
* Retrieves 64-bits of true random data from RDSEED instruction.
|
||||
*
|
||||
* If RDSEED isn't available, we'll try RDRAND (which we automatically
|
||||
* disable for microarchitectures where it's known to be slow or buggy).
|
||||
* If RDRAND isn't available then we try getrandom(), RtlGenRandom(), or
|
||||
* sysctl(KERN_ARND). If those aren't available then we try /dev/urandom
|
||||
* and if that fails, we use RDTSC and getpid().
|
||||
*
|
||||
* This function takes about 32 nanoseconds.
|
||||
*
|
||||
* @see rngset(), rdrand(), rand64()
|
||||
*/
|
||||
uint64_t rdseed(void) {
|
||||
register uint64_t x;
|
||||
volatile uint64_t b;
|
||||
if (getrandom(&b, 8, GRND_NONBLOCK | GRND_RANDOM) == 8) {
|
||||
x = b;
|
||||
b = 0;
|
||||
} else {
|
||||
x = (uint64_t)rand() << 62 | (uint64_t)rand() << 31 | rand();
|
||||
int i;
|
||||
char cf;
|
||||
uint64_t x;
|
||||
if (X86_HAVE(RDSEED)) {
|
||||
for (i = 0; i < 10; ++i) {
|
||||
asm volatile(CFLAG_ASM("rdseed\t%1")
|
||||
: CFLAG_CONSTRAINT(cf), "=r"(x)
|
||||
: /* no inputs */
|
||||
: "cc");
|
||||
if (cf) return x;
|
||||
asm volatile("pause");
|
||||
}
|
||||
}
|
||||
return x;
|
||||
return rdrand();
|
||||
}
|
||||
|
|
30
libc/rand/real1.c
Normal file
30
libc/rand/real1.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
/**
|
||||
* Generates number on [0,1]-real-interval, e.g.
|
||||
*
|
||||
* double x = _real1(vigna())
|
||||
*
|
||||
* @see vigna(), mt19937()
|
||||
*/
|
||||
double _real1(uint64_t x) {
|
||||
return 1. / 9007199254740991. * (x >> 11);
|
||||
}
|
30
libc/rand/real2.c
Normal file
30
libc/rand/real2.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
/**
|
||||
* Generates number on [0,1)-real-interval, e.g.
|
||||
*
|
||||
* double x = _real2(vigna())
|
||||
*
|
||||
* @see vigna(), mt19937()
|
||||
*/
|
||||
double _real2(uint64_t x) {
|
||||
return 1. / 9007199254740992. * (x >> 11);
|
||||
}
|
30
libc/rand/real3.c
Normal file
30
libc/rand/real3.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
/**
|
||||
* Generates number on (0,1)-real-interval, e.g.
|
||||
*
|
||||
* double x = _real3(vigna())
|
||||
*
|
||||
* @see vigna(), mt19937()
|
||||
*/
|
||||
double _real3(uint64_t x) {
|
||||
return 1. / 4503599627370496. * ((x >> 12) + .5);
|
||||
}
|
|
@ -16,40 +16,75 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/rand/xorshift.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Fills memory with random bytes, e.g.
|
||||
*
|
||||
* char buf[1024];
|
||||
* rngset(buf, sizeof(buf), rand64, -1);
|
||||
* char buf[512];
|
||||
* rngset(buf, sizeof(buf), 0, 0);
|
||||
*
|
||||
* If reseed is zero then the internal PRNG is disabled and bytes are
|
||||
* simply copied in little-endian order from the seed function. If seed
|
||||
* is NULL then the reseed parameter is used as the seed value for the
|
||||
* internal PRNG. If seed!=NULL and reseed>8 then reseed is the number
|
||||
* of bytes after which the seed() function should be called again, to
|
||||
* freshen up the PRNG.
|
||||
*
|
||||
* The main advantage of this generator is that it produces data at 13
|
||||
* gigabytes per second since Vigna's Algorithm vectorizes better than
|
||||
* alternatives, going even faster than xorshift.
|
||||
*
|
||||
* @param seed can be rand64() and is always called at least once
|
||||
* @param reseed is bytes between seed() calls and -1 disables it
|
||||
* @return original buf
|
||||
*/
|
||||
void *rngset(void *buf, size_t size, uint64_t seed(void), size_t reseed) {
|
||||
unsigned char *p;
|
||||
uint64_t i, x, state;
|
||||
p = buf;
|
||||
state = seed();
|
||||
for (i = 0; size - i >= sizeof(x); i += sizeof(x)) {
|
||||
x = MarsagliaXorshift64(&state);
|
||||
memcpy(p + i, &x, sizeof(x));
|
||||
if (i >= reseed) {
|
||||
state = seed();
|
||||
p += i;
|
||||
size -= i;
|
||||
i = 0;
|
||||
void *rngset(void *b, size_t n, uint64_t seed(void), size_t reseed) {
|
||||
size_t m;
|
||||
uint64_t i, x, t = 0;
|
||||
unsigned char *p = b;
|
||||
if (!seed) {
|
||||
t = reseed;
|
||||
reseed = -1;
|
||||
} else if (reseed < 8) {
|
||||
reseed = 8;
|
||||
}
|
||||
while (n) {
|
||||
if (seed) t = seed();
|
||||
if (!seed || reseed > 8) {
|
||||
n -= (m = reseed < n ? reseed : n);
|
||||
while (m >= 8) {
|
||||
x = (t += 0x9e3779b97f4a7c15);
|
||||
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
|
||||
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
|
||||
x = (x ^ (x >> 31));
|
||||
__builtin_memcpy(p, &x, 8);
|
||||
p += 8;
|
||||
m -= 8;
|
||||
}
|
||||
while (m--) {
|
||||
*p++ = t;
|
||||
t >>= 8;
|
||||
}
|
||||
} else if (n >= 8) {
|
||||
p[0] = (0x00000000000000FF & t) >> 000;
|
||||
p[1] = (0x000000000000FF00 & t) >> 010;
|
||||
p[2] = (0x0000000000FF0000 & t) >> 020;
|
||||
p[3] = (0x00000000FF000000 & t) >> 030;
|
||||
p[4] = (0x000000FF00000000 & t) >> 040;
|
||||
p[5] = (0x0000FF0000000000 & t) >> 050;
|
||||
p[6] = (0x00FF000000000000 & t) >> 060;
|
||||
p[7] = (0xFF00000000000000 & t) >> 070;
|
||||
p += 8;
|
||||
n -= 8;
|
||||
} else {
|
||||
while (n) {
|
||||
*p++ = t;
|
||||
t >>= 8;
|
||||
--n;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i < size) {
|
||||
x = MarsagliaXorshift64(&state);
|
||||
for (; i < size; ++i, x >>= 8) {
|
||||
p[i] = x & 0xff;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
return b;
|
||||
}
|
||||
|
|
77
libc/rand/vigna.c
Normal file
77
libc/rand/vigna.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/xadd.h"
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
static uint64_t g_vigna;
|
||||
|
||||
/**
|
||||
* Returns deterministic pseudorandom data, e.g.
|
||||
*
|
||||
* uint64_t x = vigna();
|
||||
*
|
||||
* You can generate different types of numbers as follows:
|
||||
*
|
||||
* int64_t x = vigna() >> 1; // make positive signed integer
|
||||
* double x = _real1(vigna()); // make float on [0,1]-interval
|
||||
*
|
||||
* You can seed this random number generator using:
|
||||
*
|
||||
* svigna(rdseed());
|
||||
*
|
||||
* You may use the reentrant version of this function:
|
||||
*
|
||||
* static uint64_t s = 0;
|
||||
* uint64_t x = svigna_r(&s);
|
||||
*
|
||||
* This function is the fastest way to generate good scalar pseudorandom
|
||||
* numbers that aren't truncated. If you want to fill a buffer with data
|
||||
* then rngset() implements vigna's algorithm to do that extremely well:
|
||||
*
|
||||
* char buf[4096];
|
||||
* rngset(buf, sizeof(buf), vigna, 0);
|
||||
*
|
||||
* If you want a fast pseudorandom number generator that seeds itself
|
||||
* automatically on startup and fork() then consider rand64(). If you
|
||||
* want true random data then consider rdseed, rdrand, and getrandom.
|
||||
*
|
||||
* @return 64 bits of pseudorandom data
|
||||
*/
|
||||
uint64_t vigna(void) {
|
||||
return vigna_r(&g_vigna);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pseudorandom data.
|
||||
* @see vigna() for easy api
|
||||
*/
|
||||
uint64_t vigna_r(uint64_t state[hasatleast 1]) {
|
||||
uint64_t z = (state[0] += 0x9e3779b97f4a7c15);
|
||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
||||
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeds vigna() pseudorandom number generator.
|
||||
* @see vigna(), vigna_r()
|
||||
*/
|
||||
void svigna(uint64_t seed) {
|
||||
g_vigna = seed;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue