rng.fs 2.84 KB
Newer Older
1 2
\ generic rng

bernd's avatar
bernd committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
\ Copyright (C) 2010-2014   Bernd Paysan

\ This program is free software: you can redistribute it and/or modify
\ it under the terms of the GNU Affero General Public License as published by
\ the Free Software Foundation, either version 3 of the License, or
\ (at your option) any later version.

\ 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 Affero General Public License for more details.

\ You should have received a copy of the GNU Affero General Public License
\ along with this program.  If not, see <http://www.gnu.org/licenses/>.

\ The general idea here is: You use an entropy source to initialize your PRNG.
\ The entropy source used here is /dev/urandom.  After initializing the PRNG,
\ you make sure that no observer can influence your PRNG, i.e. you stop
\ reading entropy.

\ The PRNG itself works by repeatedly encrypting the same block of memory
\ using Keccak in duplex mode.  This is a huge amount of state (1.2kB),
\ of which the 200 bytes Keccak state is kept hidden.

bernd's avatar
bernd committed
27 28
require unix/pthread.fs

29 30 31 32
$400 Constant rngbuf#

s" /dev/urandom" r/o open-file throw Value rng-fd

bernd's avatar
bernd committed
33 34
User rng-pos
User rng-buffer
bernd's avatar
bernd committed
35 36
User rng-pid
User rng-task
bernd's avatar
bernd committed
37
User rng-key
38
rngbuf# rng-pos !
39

bernd's avatar
bernd committed
40 41 42 43
: rng-allot ( -- )
    rngbuf# allocate throw rng-buffer !
    c:key# allocate throw rng-key !
    rngbuf# rng-pos !
bernd's avatar
bernd committed
44
    getpid rng-pid ! up@ rng-task ! ;
45

46 47
: rng-exec ( xt -- )
    c:key@ >r  rng-key @ c:key!  catch  r> c:key!  throw ;
48

bernd's avatar
bernd committed
49 50
: rng-init ( -- )
    rng-buffer @ rngbuf# rng-fd read-file throw drop ;
51 52

: rng-step ( -- )
53
    [: ( rng-init ) \ djb advices *not* to do this here
bernd's avatar
bernd committed
54 55
       rng-buffer @ rngbuf# c:encrypt
       rng-pos off ;] rng-exec ;
56 57 58 59

\ init rng to be actually useful

: random-init ( -- )
60
    rng-key @ c:key# rng-fd read-file throw drop ;
61

bernd's avatar
bernd committed
62
: read-initrng ( fd -- flag )  { fd }
63
    0. fd reposition-file throw
64 65
    rng-key @ c:key# fd read-file throw c:key# =
    c:diffuse  fd close-file throw ;
66

bernd's avatar
bernd committed
67 68 69
: write-initrng ( -- )
    s" ~/.initrng" r/w create-file throw >r
    rng-key @ c:key# r@ write-file throw
70 71 72
    r> close-file throw ;

: salt-init ( -- )
bernd's avatar
bernd committed
73 74
    s" ~/.initrng" r/o open-file IF  drop random-init
    ELSE  read-initrng  0= IF  random-init  THEN  THEN
75
    rng-init rng-step write-initrng rng-init rng-step ;
bernd's avatar
bernd committed
76 77 78 79

\ buffered random numbers to output 64 bit at a time

: rng-step? ( n -- )
80 81 82
    up@ rng-task @ <> getpid rng-pid @ <> or
    IF  rng-allot salt-init  THEN
    rngbuf# u> IF  rng-step  THEN ;
bernd's avatar
bernd committed
83 84 85

: rng@ ( -- x )
    rng-pos @ 64aligned 64'+ rng-step?
86 87
    rng-pos @ 64aligned dup 64'+ rng-pos !
    rng-buffer @ + 64@ ;
bernd's avatar
bernd committed
88 89 90 91 92 93 94 95 96

: rng$ ( u -- addr u ) >r
    rng-pos @ r@ + rng-step?
    rng-buffer @ rng-pos @ + r> dup rng-pos +! ;

: rng32 ( -- x )
    rng-pos @ 4 + rng-step?
    rng-pos @ rng-buffer @ + l@
    4 rng-pos +! ;