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:
Justine Tunney 2021-09-27 22:58:51 -07:00
parent fa7b4f5bd1
commit 39bf41f4eb
806 changed files with 77494 additions and 63859 deletions

View file

@ -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;
}

View file

@ -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
View 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;
}

View file

@ -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) */

View file

@ -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))

View file

@ -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};

View file

@ -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
View 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};

View file

@ -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
View 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
View 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
View 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);
}

View file

@ -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
View 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;
}