Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

54
libc/rand/devrand.c Normal file
View file

@ -0,0 +1,54 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/rand/rand.h"
#include "libc/str/str.h"
#include "libc/calls/internal.h"
#include "libc/calls/calls.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
/**
* Reads random bytes from system pseudo random number api.
* @return 0 on success or -1 w/ errno
*/
int devrand(void *buf, size_t size) {
int fd;
size_t got;
ssize_t rc;
unsigned char *p, *pe;
fd = -1;
if (IsWindows()) return enosys();
if ((fd = openat$sysv(AT_FDCWD, "/dev/urandom", O_RDONLY, 0)) == -1) {
return -1;
}
p = buf;
pe = p + size;
while (p < pe) {
if ((rc = read$sysv(fd, p, pe - p)) == -1) break;
if (!(got = (size_t)rc)) break;
p += got;
}
close$sysv(fd);
return p == pe ? 0 : -1;
}

32
libc/rand/g_rando.S Normal file
View file

@ -0,0 +1,32 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/notice.inc"
.yoink __FILE__
.bss
.align 8
g_rando:.quad 0
.endobj g_rando,globl,hidden
.previous
.init.start 100,_init_g_rando
movq $1,g_rando(%rip)
.init.end 100,_init_g_rando

48
libc/rand/g_rando32.c Normal file
View file

@ -0,0 +1,48 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/rand/rand.h"
#include "libc/rand/xorshift.h"
#include "libc/sysv/consts/auxv.h"
hidden uint32_t g_rando32;
textstartup static void g_rando32_init() {
register intptr_t *auxv asm("r15"); /* @see libc/crt/crt.S */
asm volatile("" : "=r"(auxv));
if (!IsXnu() && !IsWindows()) {
for (intptr_t *auxvp = auxv; auxvp[0]; auxvp += 2) {
if (auxvp[0] == AT_RANDOM) {
uint8_t(*sysrandseed)[16] = (uint8_t(*)[16])auxvp[1];
if (sysrandseed) g_rando32 ^= read32le(&(*sysrandseed)[8]);
return;
}
}
}
g_rando32 ^= kMarsagliaXorshift32Seed;
if (IsWindows()) {
g_rando32 ^= winrandish();
} else {
devrand(&g_rando32, sizeof(g_rando32));
}
}
const void *const g_rando32_ctor[] initarray = {g_rando32_init};

48
libc/rand/g_rando64.c Normal file
View file

@ -0,0 +1,48 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/rand/rand.h"
#include "libc/rand/xorshift.h"
#include "libc/sysv/consts/auxv.h"
hidden uint64_t g_rando64;
textstartup static void g_rando64_init() {
register intptr_t *auxv asm("r15"); /* @see libc/crt/crt.S */
asm volatile("" : "=r"(auxv));
if (!IsXnu() && !IsWindows()) {
for (intptr_t *auxvp = auxv; auxvp[0]; auxvp += 2) {
if (auxvp[0] == AT_RANDOM) {
uint8_t(*sysrandseed)[16] = (uint8_t(*)[16])auxvp[1];
if (sysrandseed) g_rando64 ^= read64le(&(*sysrandseed)[0]);
return;
}
}
}
g_rando64 ^= kMarsagliaXorshift64Seed;
if (IsWindows()) {
g_rando64 ^= winrandish();
} else {
devrand(&g_rando64, sizeof(g_rando64));
}
}
const void *const g_rando64_ctor[] initarray = {g_rando64_init};

29
libc/rand/getentropy.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/rand/rand.h"
#include "libc/sysv/consts/grnd.h"
/**
* Returns random seeding bytes, the XNU/OpenBSD way.
* @see getrandom()
*/
int getentropy(void *buf, size_t size) {
return getrandom(buf, size, GRND_RANDOM);
}

51
libc/rand/getrandom.c Normal file
View file

@ -0,0 +1,51 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/rand/rand.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
/**
* Returns random bytes appropriate for random seeding.
*
* @param size should be the smallest value that meets your requirements
* @param flags may be GRND_{RANDOM,NONBLOCK}
* @return number of bytes copied on success; or -1 w/ errno, which
* indicates only that the request couldn't be serviced by the host
* kernel; this wrapper will still fill the buffer with random bytes
* from fallback sources no matter what
*/
ssize_t getrandom(void *buf, size_t size, unsigned flags) {
ssize_t rc = getrandom$sysv(buf, size, flags);
size_t i = rc == -1 ? 0 : (size_t)rc;
if (i > size) abort();
if (i < size) {
unsigned char *p = buf;
int olderr = errno;
do {
uint64_t i64 = rand64();
memcpy(&p[i], &i64, min(sizeof(i64), size - i));
} while ((i += sizeof(uint64_t)) < size);
errno = olderr;
}
return rc;
}

10
libc/rand/internal.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_RAND_INTERNAL_H_
#define COSMOPOLITAN_LIBC_RAND_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
hidden extern uint64_t g_rando;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RAND_INTERNAL_H_ */

16
libc/rand/lcg.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_LCG_H_
#define COSMOPOLITAN_LIBC_LCG_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
forceinline uint64_t KnuthLinearCongruentialGenerator(uint64_t prev[1]) {
/* Knuth, D.E., "The Art of Computer Programming," Vol 2,
Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
p. 106 (line 26) & p. 108 */
prev[0] = prev[0] * 6364136223846793005 + 1442695040888963407;
return prev[0];
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LCG_H_ */

142
libc/rand/poz.c Normal file
View file

@ -0,0 +1,142 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
vi: set et ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi
*/
/* clang-format off */
/*
Compute probability of measured Chi Square value.
This code was developed by Gary Perlman of the Wang
Institute (full citation below) and has been minimally
modified for use in this program.
*/
#include "libc/math.h"
/*HEADER
Module: z.c
Purpose: compute approximations to normal z distribution probabilities
Programmer: Gary Perlman
Organization: Wang Institute, Tyngsboro, MA 01879
Copyright: none
Tabstops: 4
*/
#define Z_MAX 6.0 /* maximum meaningful z value */
/*FUNCTION poz: probability of normal z value */
/*ALGORITHM
Adapted from a polynomial approximation in:
Ibbetson D, Algorithm 209
Collected Algorithms of the CACM 1963 p. 616
Note:
This routine has six digit accuracy, so it is only useful for absolute
z values < 6. For z values >= to 6.0, poz() returns 0.0.
*/
static double /*VAR returns cumulative probability from -oo to z */
poz(const double z) /*VAR normal z value */
{
double y, x, w;
if (z == 0.0) {
x = 0.0;
} else {
y = 0.5 * fabs(z);
if (y >= (Z_MAX * 0.5)) {
x = 1.0;
} else if (y < 1.0) {
w = y * y;
x = ((((((((0.000124818987 * w
-0.001075204047) * w +0.005198775019) * w
-0.019198292004) * w +0.059054035642) * w
-0.151968751364) * w +0.319152932694) * w
-0.531923007300) * w +0.797884560593) * y * 2.0;
} else {
y -= 2.0;
x = (((((((((((((-0.000045255659 * y
+0.000152529290) * y -0.000019538132) * y
-0.000676904986) * y +0.001390604284) * y
-0.000794620820) * y -0.002034254874) * y
+0.006549791214) * y -0.010557625006) * y
+0.011630447319) * y -0.009279453341) * y
+0.005353579108) * y -0.002141268741) * y
+0.000535310849) * y +0.999936657524;
}
}
return (z > 0.0 ? ((x + 1.0) * 0.5) : ((1.0 - x) * 0.5));
}
/*
Module: chisq.c
Purpose: compute approximations to chisquare distribution probabilities
Contents: pochisq()
Uses: poz() in z.c (Algorithm 209)
Programmer: Gary Perlman
Organization: Wang Institute, Tyngsboro, MA 01879
Copyright: none
Tabstops: 4
*/
#define LOG_SQRT_PI 0.5723649429247000870717135 /* log (sqrt (pi)) */
#define I_SQRT_PI 0.5641895835477562869480795 /* 1 / sqrt (pi) */
#define BIGX 20.0 /* max value to represent exp (x) */
#define ex(x) (((x) < -BIGX) ? 0.0 : exp(x))
/*FUNCTION pochisq: probability of chi sqaure value */
/*ALGORITHM Compute probability of chi square value.
Adapted from:
Hill, I. D. and Pike, M. C. Algorithm 299
Collected Algorithms for the CACM 1967 p. 243
Updated for rounding errors based on remark in
ACM TOMS June 1985, page 185
*/
double pochisq(
const double ax, /* obtained chi-square value */
const int df /* degrees of freedom */
)
{
double x = ax;
double a, y, s;
double e, c, z;
int even; /* true if df is an even number */
y = 0.0; /* XXX: blind modification due to GCC error */
if (x <= 0.0 || df < 1) {
return 1.0;
}
a = 0.5 * x;
even = (2 * (df / 2)) == df;
if (df > 1) {
y = ex(-a);
}
s = (even ? y : (2.0 * poz(-sqrt(x))));
if (df > 2) {
x = 0.5 * (df - 1.0);
z = (even ? 1.0 : 0.5);
if (a > BIGX) {
e = (even ? 0.0 : LOG_SQRT_PI);
c = log(a);
while (z <= x) {
e = log(z) + e;
s += ex(c * z - a - e);
z += 1.0;
}
return (s);
} else {
e = (even ? 1.0 : (I_SQRT_PI / sqrt(a)));
c = 0.0;
while (z <= x) {
e = e * (a / z);
c = c + e;
z += 1.0;
}
return (c * y + s);
}
} else {
return s;
}
}

36
libc/rand/rand.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef COSMOPOLITAN_LIBC_RAND_RAND_H_
#define COSMOPOLITAN_LIBC_RAND_RAND_H_
#include "libc/ncabi.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § random
*/
#define RAND_MAX __INT_MAX__ /* only applies to rand() */
void srand(uint64_t) nothrow nocallback; /* seeds rand() only */
int rand(void) nothrow nocallback; /* ≥0 unseeded lcg prng */
uint32_t rand32(void) nothrow nocallback; /* random as possible rng */
uint64_t rand64(void) nothrow nocallback; /* random as possible rng */
double poz(double); /* verify our claims */
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);
int devrand(void *, size_t);
int64_t winrandish(void);
uint64_t rdrand(void);
float randf(void);
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
NCABI_DECLARE_0(NCABI_NOPRUNE, int, __rand, "rand")
#define rand() __rand()
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RAND_RAND_H_ */

54
libc/rand/rand.mk Normal file
View file

@ -0,0 +1,54 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += LIBC_RAND
LIBC_RAND_ARTIFACTS += LIBC_RAND_A
LIBC_RAND = $(LIBC_RAND_A_DEPS) $(LIBC_RAND_A)
LIBC_RAND_A = o/$(MODE)/libc/rand/rand.a
LIBC_RAND_A_FILES := $(wildcard libc/rand/*)
LIBC_RAND_A_HDRS = $(filter %.h,$(LIBC_RAND_A_FILES))
LIBC_RAND_A_SRCS_S = $(filter %.S,$(LIBC_RAND_A_FILES))
LIBC_RAND_A_SRCS_C = $(filter %.c,$(LIBC_RAND_A_FILES))
LIBC_RAND_A_SRCS = \
$(LIBC_RAND_A_SRCS_S) \
$(LIBC_RAND_A_SRCS_C)
LIBC_RAND_A_OBJS = \
$(LIBC_RAND_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_RAND_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_RAND_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_RAND_A_CHECKS = \
$(LIBC_RAND_A).pkg \
$(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_RAND_A_DIRECTDEPS = \
LIBC_STUBS \
LIBC_TINYMATH \
LIBC_NEXGEN32E \
LIBC_NT_KERNELBASE \
LIBC_SYSV_CALLS \
LIBC_SYSV
LIBC_RAND_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x))))
$(LIBC_RAND_A): libc/rand/ \
$(LIBC_RAND_A).pkg \
$(LIBC_RAND_A_OBJS)
$(LIBC_RAND_A).pkg: \
$(LIBC_RAND_A_OBJS) \
$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x)_A).pkg)
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))
LIBC_RAND_CHECKS = $(foreach x,$(LIBC_RAND_ARTIFACTS),$($(x)_CHECKS))
LIBC_RAND_OBJS = $(foreach x,$(LIBC_RAND_ARTIFACTS),$($(x)_OBJS))
$(LIBC_RAND_OBJS): $(BUILD_FILES) libc/rand/rand.mk
.PHONY: o/$(MODE)/libc/rand
o/$(MODE)/libc/rand: $(LIBC_RAND_CHECKS)

31
libc/rand/rand.ncabi.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/rand/internal.h"
#include "libc/rand/lcg.h"
#include "libc/rand/rand.h"
/**
* Returns 31-bit random number using a linear congruential generator.
*
* Please note that, unlike rand32(), the rand() function uses the same
* seed at startup by default, unless srand() is called. This makes it
* useful in cases where deterministic behavior is needed.
*/
int(rand)(void) { return KnuthLinearCongruentialGenerator(&g_rando) >> 33; }

42
libc/rand/rand32.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/rand/rand.h"
#include "libc/rand/xorshift.h"
/**
* This function is an independent 32-bit clone of rand64().
*/
nodebuginfo uint32_t(rand32)(void) {
uint32_t res;
if (X86_HAVE(RDRND)) {
res = rdrand();
} else {
if (IsWindows()) {
res = kMarsagliaXorshift32Seed ^ winrandish();
} else {
devrand(&res, sizeof(res));
}
hidden extern uint32_t g_rando32;
res ^= MarsagliaXorshift32(&g_rando32);
}
return res;
}

49
libc/rand/rand64.c Normal file
View file

@ -0,0 +1,49 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/rand/rand.h"
#include "libc/rand/xorshift.h"
/**
* Returns nondeterministic random number.
*
* This function uses a good random source if it's available, which
* takes ~400 cycles (~99ns). Otherwise it's seeded at program start
* with the system provided random value and may perform a few
* microseconds worth of system calls to get a good value.
*
* @see rngset()
*/
nodebuginfo uint64_t(rand64)(void) {
uint64_t res;
if (X86_HAVE(RDRND)) {
res = rdrand();
} else {
if (IsWindows()) {
res = winrandish();
} else {
devrand(&res, sizeof(res));
}
hidden extern uint64_t g_rando64;
res ^= MarsagliaXorshift64(&g_rando64);
}
return res;
}

28
libc/rand/randf.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/limits.h"
#include "libc/rand/internal.h"
#include "libc/rand/lcg.h"
#include "libc/rand/rand.h"
float randf(void) {
return (float)(int)(KnuthLinearCongruentialGenerator(&g_rando) >> 32) /
INT_MAX;
}

22
libc/rand/rando.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/rand/internal.h"
uint64_t g_rando;

184
libc/rand/randtest.c Normal file
View file

@ -0,0 +1,184 @@
/* clang-format off */
/*
Apply various randomness tests to a stream of bytes
by John Walker -- September 1996
http://www.fourmilab.ch/
*/
#include "libc/math.h"
#define FALSE 0
#define TRUE 1
#define log2of10 3.32192809488736234787
static int binary = FALSE; /* Treat input as a bitstream */
static long ccount[256], /* Bins to count occurrences of values */
totalc = 0; /* Total bytes counted */
static double prob[256]; /* Probabilities per bin for entropy */
/* RT_LOG2 -- Calculate log to the base 2 */
static double rt_log2(double x)
{
return log2of10 * log10(x);
}
#define MONTEN 6 /* Bytes used as Monte Carlo
co-ordinates. This should be no more
bits than the mantissa of your
"double" floating point type. */
static int mp, sccfirst;
static unsigned int monte[MONTEN];
static long inmont, mcount;
static double cexp_, incirc, montex, montey, montepi,
scc, sccun, sccu0, scclast, scct1, scct2, scct3,
ent, chisq, datasum;
/* RT_INIT -- Initialise random test counters. */
void rt_init(int binmode)
{
int i;
binary = binmode; /* Set binary / byte mode */
/* Initialise for calculations */
ent = 0.0; /* Clear entropy accumulator */
chisq = 0.0; /* Clear Chi-Square */
datasum = 0.0; /* Clear sum of bytes for arithmetic mean */
mp = 0; /* Reset Monte Carlo accumulator pointer */
mcount = 0; /* Clear Monte Carlo tries */
inmont = 0; /* Clear Monte Carlo inside count */
incirc = 65535.0 * 65535.0;/* In-circle distance for Monte Carlo */
sccfirst = TRUE; /* Mark first time for serial correlation */
scct1 = scct2 = scct3 = 0.0; /* Clear serial correlation terms */
incirc = pow(pow(256.0, (double) (MONTEN / 2)) - 1, 2.0);
for (i = 0; i < 256; i++) {
ccount[i] = 0;
}
totalc = 0;
}
/* RT_ADD -- Add one or more bytes to accumulation. */
void rt_add(void *buf, int bufl)
{
unsigned char *bp = buf;
int oc, c, bean;
while (bean = 0, (bufl-- > 0)) {
oc = *bp++;
do {
if (binary) {
c = !!(oc & 0x80);
} else {
c = oc;
}
ccount[c]++; /* Update counter for this bin */
totalc++;
/* Update inside / outside circle counts for Monte Carlo
computation of PI */
if (bean == 0) {
monte[mp++] = oc; /* Save character for Monte Carlo */
if (mp >= MONTEN) { /* Calculate every MONTEN character */
int mj;
mp = 0;
mcount++;
montex = montey = 0;
for (mj = 0; mj < MONTEN / 2; mj++) {
montex = (montex * 256.0) + monte[mj];
montey = (montey * 256.0) + monte[(MONTEN / 2) + mj];
}
if ((montex * montex + montey * montey) <= incirc) {
inmont++;
}
}
}
/* Update calculation of serial correlation coefficient */
sccun = c;
if (sccfirst) {
sccfirst = FALSE;
scclast = 0;
sccu0 = sccun;
} else {
scct1 = scct1 + scclast * sccun;
}
scct2 = scct2 + sccun;
scct3 = scct3 + (sccun * sccun);
scclast = sccun;
oc <<= 1;
} while (binary && (++bean < 8));
}
}
/* RT_END -- Complete calculation and return results. */
void rt_end(double *r_ent, double *r_chisq, double *r_mean,
double *r_montepicalc, double *r_scc)
{
int i;
/* Complete calculation of serial correlation coefficient */
scct1 = scct1 + scclast * sccu0;
scct2 = scct2 * scct2;
scc = totalc * scct3 - scct2;
if (scc == 0.0) {
scc = -100000;
} else {
scc = (totalc * scct1 - scct2) / scc;
}
/* Scan bins and calculate probability for each bin and
Chi-Square distribution. The probability will be reused
in the entropy calculation below. While we're at it,
we sum of all the data which will be used to compute the
mean. */
cexp_ = totalc / (binary ? 2.0 : 256.0); /* Expected count per bin */
for (i = 0; i < (binary ? 2 : 256); i++) {
double a = ccount[i] - cexp_;
prob[i] = ((double) ccount[i]) / totalc;
chisq += (a * a) / cexp_;
datasum += ((double) i) * ccount[i];
}
/* Calculate entropy */
for (i = 0; i < (binary ? 2 : 256); i++) {
if (prob[i] > 0.0) {
ent += prob[i] * rt_log2(1 / prob[i]);
}
}
/* Calculate Monte Carlo value for PI from percentage of hits
within the circle */
montepi = 4.0 * (((double) inmont) / mcount);
/* Return results through arguments */
*r_ent = ent;
*r_chisq = chisq;
*r_mean = datasum / totalc;
*r_montepicalc = montepi;
*r_scc = scc;
}

47
libc/rand/rdrand.c Normal file
View file

@ -0,0 +1,47 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/rand/rand.h"
/**
* Intel Secure Key Digital Random Number Generator
* Introduced w/ Ivy Bridge c. 2013 and Excavator c. 2015
* @see rand32(), rand64(), and randcpy()
*/
uint64_t rdrand(void) {
char cf;
size_t i;
uint64_t res;
assert(X86_HAVE(RDRND));
for (;;) {
for (i = 0; i < 10; ++i) {
/* CF=1: Destination register valid. Quoth Intel DRNG-SIG 4.1.3 */
asm volatile(CFLAG("rdrand\t%1")
: CF(cf), "=r"(res)
: /* no inputs */
: "cc");
if (cf) return res;
}
asm volatile("rep nop"); /* unlikely 140 cycle spin */
}
}

54
libc/rand/rngset.c Normal file
View file

@ -0,0 +1,54 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/rand/rand.h"
#include "libc/rand/xorshift.h"
#include "libc/str/str.h"
/**
* Fills memory with random bytes.
*
* @param seed can be rand64
* @param reseed is number of bytes between seed() calls
* @return buf
*/
void *rngset(void *buf, size_t size, uint64_t (*seed)(void), size_t reseed) {
unsigned char *p;
uint64_t i, x, state;
i = 0;
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;
}
}
if (i < size) {
x = MarsagliaXorshift64(&state);
for (; i < size; ++i, x >>= 8) {
p[i] = x & 0xff;
}
}
return buf;
}

27
libc/rand/srand.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/rand/rand.h"
extern uint64_t g_rando;
/**
* Seeds random number generator that's used by rand().
*/
void(srand)(uint64_t seed) { g_rando = seed; }

30
libc/rand/strfry.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/shuffle.h"
#include "libc/rand/rand.h"
#include "libc/str/str.h"
/**
* Jumbles up string.
*/
char *strfry(char *s) {
shuffle(rand, s, strlen(s));
return s;
}

44
libc/rand/winrandish.c Normal file
View file

@ -0,0 +1,44 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nt/dll.h"
#include "libc/nt/events.h"
#include "libc/nt/struct/point.h"
#include "libc/nt/struct/teb.h"
#include "libc/rand/rand.h"
/**
* Returns somewhat randomish number on Windows.
*/
textwindows int64_t winrandish(void) {
int64_t res;
struct NtPoint point;
res = ((int64_t)NtGetPid() << 17) ^ NtGetTid() ^ rdtsc();
/*
* This function is intended for older CPUs built before 2012, so
* let's avoid having our CUI apps yoink USER32.DLL until we're
* certain we need it, thus avoiding a hundred lines of noise in
* NtTrace.exe output.
*/
typeof(GetCursorPos) *GetCursorPos_ =
GetProcAddress(GetModuleHandle("user32.dll"), "GetCursorPos");
if (GetCursorPos_ && GetCursorPos_(&point)) res ^= point.x * point.y;
return res;
}

28
libc/rand/xorshift.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef COSMOPOLITAN_LIBC_RAND_XORSHIFT_H_
#define COSMOPOLITAN_LIBC_RAND_XORSHIFT_H_
#define kMarsagliaXorshift64Seed 88172645463325252
#define kMarsagliaXorshift32Seed 2463534242
#if !(__ASSEMBLER__ + __LINKER__ + 0)
forceinline uint64_t MarsagliaXorshift64(uint64_t state[hasatleast 1]) {
uint64_t x = state[0];
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
state[0] = x;
return x;
}
forceinline uint32_t MarsagliaXorshift32(uint32_t state[hasatleast 1]) {
uint32_t x = state[0];
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
state[0] = x;
return x;
}
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RAND_XORSHIFT_H_ */