ref: 0a5f81a44230cbd562b6d71a0a5be018e24a5ba6
parent: 71ac88392f2033256b29f22bd8afdd7374100e5a
author: cinap_lenrek <[email protected]>
date: Sat Aug 27 16:42:31 EDT 2016
kernel: switch to fast portable chacha based seed-once random number generator
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -872,6 +872,11 @@
fprestore = fpx87restore;
}
+ if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0)
+ hwrandbuf = rdrandbuf;
+ else
+ hwrandbuf = nil;
+
cputype = t;
return t->family;
}
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -32,6 +32,7 @@
proc.$O\
qio.$O\
qlock.$O\
+ random.$O\
rdb.$O\
rebootcmd.$O\
segment.$O\
@@ -52,7 +53,6 @@
memory.$O\
mmu.$O\
trap.$O\
- pcrandom.$O\
$CONF.root.$O\
$CONF.rootc.$O\
$DEVS\
--- a/sys/src/9/pc/pcrandom.c
+++ /dev/null
@@ -1,152 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-
-static int haverdrand;
-
-struct Rb
-{
- QLock;
- Rendez producer;
- Rendez consumer;
- ulong randomcount;
- uchar buf[128];
- uchar *ep;
- uchar *rp;
- uchar *wp;
- uchar next;
- uchar wakeme;
- ushort bits;
- ulong randn;
-} rb;
-
-static int
-rbnotfull(void*)
-{
- int i;
-
- i = rb.rp - rb.wp;
- return i != 1 && i != (1 - sizeof(rb.buf));
-}
-
-static int
-rbnotempty(void*)
-{
- return rb.wp != rb.rp;
-}
-
-static void
-genrandom(void*)
-{
- up->basepri = PriNormal;
- up->priority = up->basepri;
-
- while(waserror())
- ;
- for(;;){
- if(++rb.randomcount <= 100000)
- continue;
- if(anyhigher())
- sched();
- if(!rbnotfull(0))
- sleep(&rb.producer, rbnotfull, 0);
- }
-}
-
-/*
- * produce random bits in a circular buffer
- */
-static void
-randomclock(void)
-{
- if(rb.randomcount == 0 || !rbnotfull(0))
- return;
-
- rb.bits = (rb.bits<<2) ^ rb.randomcount;
- rb.randomcount = 0;
-
- rb.next++;
- if(rb.next != 8/2)
- return;
- rb.next = 0;
-
- *rb.wp ^= rb.bits;
- if(rb.wp+1 == rb.ep)
- rb.wp = rb.buf;
- else
- rb.wp = rb.wp+1;
-
- if(rb.wakeme)
- wakeup(&rb.consumer);
-}
-
-void
-randominit(void)
-{
- if(!strcmp(m->cpuidid, "GenuineIntel")
- && (m->cpuidcx & Rdrnd)){
- haverdrand = 1;
- }
- else{
- /* Frequency close but not equal to HZ */
- addclock0link(randomclock, MS2HZ+3);
- rb.ep = rb.buf + sizeof(rb.buf);
- rb.rp = rb.wp = rb.buf;
- kproc("genrandom", genrandom, 0);
- }
-}
-
-/*
- * consume random bytes from a circular buffer
- */
-ulong
-randomread(void *xp, ulong n)
-{
- uchar *e, *p;
- ulong x;
-
- p = xp;
-
- if(haverdrand){
- rdrandbuf(p, n);
- return n;
- }
-
- if(waserror()){
- qunlock(&rb);
- nexterror();
- }
-
- qlock(&rb);
- for(e = p + n; p < e; ){
- if(rb.wp == rb.rp){
- rb.wakeme = 1;
- wakeup(&rb.producer);
- sleep(&rb.consumer, rbnotempty, 0);
- rb.wakeme = 0;
- continue;
- }
-
- /*
- * beating clocks will be predictable if
- * they are synchronized. Use a cheap pseudo-
- * random number generator to obscure any cycles.
- */
- x = rb.randn*1103515245 ^ *rb.rp;
- *p++ = rb.randn = x;
-
- if(rb.rp+1 == rb.ep)
- rb.rp = rb.buf;
- else
- rb.rp = rb.rp+1;
- }
- qunlock(&rb);
- poperror();
-
- wakeup(&rb.producer);
-
- return n;
-}
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -29,6 +29,7 @@
proc.$O\
qio.$O\
qlock.$O\
+ random.$O\
rdb.$O\
rebootcmd.$O\
segment.$O\
@@ -49,7 +50,6 @@
memory.$O\
mmu.$O\
trap.$O\
- pcrandom.$O\
$CONF.root.$O\
$CONF.rootc.$O\
$DEVS\
--- a/sys/src/9/port/devcons.c
+++ b/sys/src/9/port/devcons.c
@@ -4,8 +4,8 @@
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
-#include "pool.h"
+#include <pool.h>
#include <authsrv.h>
void (*consdebug)(void) = nil;
@@ -21,7 +21,6 @@
char *sysname;
vlong fasthz;
-static void seedrand(void);
static int readtime(ulong, char*, int);
static int readbintime(char*, int);
static int writetime(char*, int);
@@ -616,7 +615,8 @@
"%lud/%lud user\n"
"%lud/%lud swap\n"
"%llud/%llud/%llud kernel malloc\n"
- "%llud/%llud/%llud kernel draw\n",
+ "%llud/%llud/%llud kernel draw\n"
+ "%llud/%llud/%llud kernel secret\n",
(uvlong)conf.npage*BY2PG,
(uvlong)BY2PG,
conf.npage-conf.upages,
@@ -627,7 +627,10 @@
(uvlong)mainmem->maxsize,
(uvlong)imagmem->curalloc,
(uvlong)imagmem->cursize,
- (uvlong)imagmem->maxsize);
+ (uvlong)imagmem->maxsize,
+ (uvlong)secrmem->curalloc,
+ (uvlong)secrmem->cursize,
+ (uvlong)secrmem->maxsize);
return readstr((ulong)offset, buf, n, tmp);
@@ -845,29 +848,20 @@
static ulong randn;
-static void
-seedrand(void)
-{
- if(!waserror()){
- randomread((void*)&randn, sizeof(randn));
- poperror();
- }
-}
-
int
-nrand(int n)
+rand(void)
{
if(randn == 0)
- seedrand();
+ randomread((void*)&randn, sizeof(randn));
randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
- return (randn>>16) % n;
+ return randn;
}
int
-rand(void)
+nrand(int n)
{
- nrand(1);
- return randn;
+ rand();
+ return (randn>>16) % n;
}
static uvlong uvorder = 0x0001020304050607ULL;
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -126,6 +126,7 @@
char* getconfenv(void);
long hostdomainwrite(char*, int);
long hostownerwrite(char*, int);
+void (*hwrandbuf)(void*, ulong);
void hzsched(void);
Block* iallocb(int);
void iallocsummary(void);
--- a/sys/src/9/port/random.c
+++ b/sys/src/9/port/random.c
@@ -5,135 +5,103 @@
#include "fns.h"
#include "../port/error.h"
-struct Rb
+#include <libsec.h>
+
+/* machine specific hardware random number generator */
+void (*hwrandbuf)(void*, ulong) = nil;
+
+static struct
{
QLock;
- Rendez producer;
- Rendez consumer;
- ulong randomcount;
- uchar buf[128];
- uchar *ep;
- uchar *rp;
- uchar *wp;
- uchar next;
- uchar wakeme;
- ushort bits;
- ulong randn;
-} rb;
+ Chachastate;
+} *rs;
-static int
-rbnotfull(void*)
+typedef struct Seedbuf Seedbuf;
+struct Seedbuf
{
- int i;
+ ulong randomcount;
+ uchar buf[64];
+ uchar nbuf;
+ uchar next;
+ ushort bits;
- i = rb.rp - rb.wp;
- return i != 1 && i != (1 - sizeof(rb.buf));
-}
+ SHA2_512state ds;
+};
-static int
-rbnotempty(void*)
+static void
+randomsample(Ureg*, Timer *t)
{
- return rb.wp != rb.rp;
+ Seedbuf *s = t->ta;
+
+ if(s->randomcount == 0 || s->nbuf >= sizeof(s->buf))
+ return;
+ s->bits = (s->bits<<2) ^ s->randomcount;
+ s->randomcount = 0;
+ if(++s->next < 8/2)
+ return;
+ s->next = 0;
+ s->buf[s->nbuf++] ^= s->bits;
}
static void
-genrandom(void*)
+randomseed(void*)
{
- up->basepri = PriNormal;
- up->priority = up->basepri;
+ Seedbuf *s;
- while(waserror())
- ;
- for(;;){
- if(++rb.randomcount <= 100000)
+ s = secalloc(sizeof(Seedbuf));
+
+ if(hwrandbuf != nil)
+ (*hwrandbuf)(s->buf, sizeof(s->buf));
+
+ /* Frequency close but not equal to HZ */
+ up->tns = (vlong)(MS2HZ+3)*1000000LL;
+ up->tmode = Tperiodic;
+ up->tt = nil;
+ up->ta = s;
+ up->tf = randomsample;
+ timeradd(up);
+ while(s->nbuf < sizeof(s->buf)){
+ if(++s->randomcount <= 100000)
continue;
if(anyhigher())
sched();
- if(!rbnotfull(0))
- sleep(&rb.producer, rbnotfull, 0);
}
-}
+ timerdel(up);
-/*
- * produce random bits in a circular buffer
- */
-static void
-randomclock(void)
-{
- if(rb.randomcount == 0 || !rbnotfull(0))
- return;
+ sha2_512(s->buf, sizeof(s->buf), s->buf, &s->ds);
+ setupChachastate(rs, s->buf, 32, s->buf+32, 12, 20);
+ qunlock(rs);
- rb.bits = (rb.bits<<2) ^ rb.randomcount;
- rb.randomcount = 0;
+ secfree(s);
- rb.next++;
- if(rb.next != 8/2)
- return;
- rb.next = 0;
-
- *rb.wp ^= rb.bits;
- if(rb.wp+1 == rb.ep)
- rb.wp = rb.buf;
- else
- rb.wp = rb.wp+1;
-
- if(rb.wakeme)
- wakeup(&rb.consumer);
+ pexit("", 1);
}
void
randominit(void)
{
- /* Frequency close but not equal to HZ */
- addclock0link(randomclock, MS2HZ+3);
- rb.ep = rb.buf + sizeof(rb.buf);
- rb.rp = rb.wp = rb.buf;
- kproc("genrandom", genrandom, 0);
+ rs = secalloc(sizeof(*rs));
+ qlock(rs); /* randomseed() unlocks once seeded */
+ kproc("randomseed", randomseed, nil);
}
-/*
- * consume random bytes from a circular buffer
- */
ulong
randomread(void *xp, ulong n)
{
- uchar *e, *p;
- ulong x;
+ if(n == 0)
+ return 0;
- p = xp;
+ if(hwrandbuf != nil)
+ (*hwrandbuf)(xp, n);
if(waserror()){
- qunlock(&rb);
+ qunlock(rs);
nexterror();
}
-
- qlock(&rb);
- for(e = p + n; p < e; ){
- if(rb.wp == rb.rp){
- rb.wakeme = 1;
- wakeup(&rb.producer);
- sleep(&rb.consumer, rbnotempty, 0);
- rb.wakeme = 0;
- continue;
- }
-
- /*
- * beating clocks will be predictable if
- * they are synchronized. Use a cheap pseudo-
- * random number generator to obscure any cycles.
- */
- x = rb.randn*1103515245 ^ *rb.rp;
- *p++ = rb.randn = x;
-
- if(rb.rp+1 == rb.ep)
- rb.rp = rb.buf;
- else
- rb.rp = rb.rp+1;
- }
- qunlock(&rb);
+ qlock(rs);
+ chacha_encrypt((uchar*)xp, n, rs);
+ qunlock(rs);
poperror();
-
- wakeup(&rb.producer);
return n;
}