X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Ftarget-random.lisp;h=f886832ca57591472fc8e2ddfbce1be94c6f5f66;hb=HEAD;hp=b4cb2780c4fc3208422d99e45618b475b1070e07;hpb=436b2ab0276f547e8537b6c1fb52b11fa1f53975;p=sbcl.git diff --git a/src/code/target-random.lisp b/src/code/target-random.lisp index b4cb278..f886832 100644 --- a/src/code/target-random.lisp +++ b/src/code/target-random.lisp @@ -85,48 +85,77 @@ (defun make-random-state (&optional state) #!+sb-doc "Make a random state object. The optional STATE argument specifies a seed - for deterministic pseudo-random number generation. +for deterministic pseudo-random number generation. - As per the Common Lisp standard, - - If STATE is NIL or not supplied or is NIL, return a copy of the default +As per the Common Lisp standard, +- If STATE is NIL or not supplied, return a copy of the default *RANDOM-STATE*. - - If STATE is a random state, return a copy of it. - - If STATE is T, return a randomly initialized state (using operating-system - provided randomness source where available, otherwise a poor substitute - based on internal time and pid) +- If STATE is a random state, return a copy of it. +- If STATE is T, return a randomly initialized state (using operating-system + provided randomness where available, otherwise a poor substitute based on + internal time and PID). - See SB-EXT:SEED-RANDOM-STATE for a SBCL extension to this functionality." +See SB-EXT:SEED-RANDOM-STATE for a SBCL extension to this functionality." (/show0 "entering MAKE-RANDOM-STATE") (check-type state (or boolean random-state)) (seed-random-state state)) +(defun fallback-random-seed () + ;; When /dev/urandom is not available, we make do with time and pid + ;; Thread ID and/or address of a CONS cell would be even better, but... + (/show0 "No /dev/urandom, using randomness from time and pid") + (+ (get-internal-real-time) + (ash (sb!unix:unix-getpid) 32))) + +#!-win32 +(defun os-random-seed () + (or + ;; On unices, we try to read from /dev/urandom and pass the results + ;; to our (simple-array (unsigned-byte 32) (*)) processor below. + ;; More than 256 bits would provide a false sense of security. + ;; If you need more bits than that, you probably also need + ;; a better algorithm too. + (ignore-errors + (with-open-file (r "/dev/urandom" :element-type '(unsigned-byte 32) + :direction :input :if-does-not-exist :error) + (let ((a (make-array '(8) :element-type '(unsigned-byte 32)))) + (assert (= 8 (read-sequence a r))) + a))) + (fallback-random-seed))) + +#!+win32 +(defun os-random-seed () + (/show0 "Getting randomness from CryptGenRandom") + (or (sb!win32:crypt-gen-random 32) + (fallback-random-seed))) + (defun seed-random-state (&optional state) #!+sb-doc "Make a random state object. The optional STATE argument specifies a seed - for deterministic pseudo-random number generation. +for deterministic pseudo-random number generation. - As per the Common Lisp standard for MAKE-RANDOM-STATE, - - If STATE is NIL or not supplied or is NIL, return a copy of the default +As per the Common Lisp standard for MAKE-RANDOM-STATE, +- If STATE is NIL or not supplied, return a copy of the default *RANDOM-STATE*. - - If STATE is a random state, return a copy of it. - - If STATE is T, return a randomly initialized state (using operating-system - provided randomness source where available, otherwise a poor substitute - based on internal time and pid) +- If STATE is a random state, return a copy of it. +- If STATE is T, return a randomly initialized state (using operating-system + provided randomness where available, otherwise a poor substitute based on + internal time and pid). - As a supported SBCL extension, we also support receiving as a seed an object - of the following types: - - (SIMPLE-ARRAY (UNSIGNED-BYTE 8) (*)) - - UNSIGNED-BYTE - While we support arguments of any size and will mix the provided bits into - the random state, it is probably overkill to provide more than 256 bits worth - of actual information. +As a supported SBCL extension, we also support receiving as a seed an object +of the following types: +- (SIMPLE-ARRAY (UNSIGNED-BYTE 8) (*)) +- UNSIGNED-BYTE +While we support arguments of any size and will mix the provided bits into +the random state, it is probably overkill to provide more than 256 bits worth +of actual information. - This particular SBCL version also accepts an argument of the following type: - - (SIMPLE-ARRAY (UNSIGNED-BYTE 32) (*)) +This particular SBCL version also accepts an argument of the following type: +(SIMPLE-ARRAY (UNSIGNED-BYTE 32) (*)) - This particular SBCL version uses the popular MT19937 PRNG algorithm, and its - internal state only effectively contains about 19937 bits of information. - http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html +This particular SBCL version uses the popular MT19937 PRNG algorithm, and its +internal state only effectively contains about 19937 bits of information. +http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html " (etypecase state ;; Easy standard cases @@ -139,26 +168,7 @@ ;; Standard case, less easy: try to randomly initialize a state. ((eql t) (/show0 "getting randomness from the operating system") - (seed-random-state - (or - ;; On unices, we try to read from /dev/urandom and pass the results - ;; to our (simple-array (unsigned-byte 32) (*)) processor below. - ;; More than 256 bits would provide a false sense of security. - ;; If you need more bits than that, you probably also need - ;; a better algorithm too. - #!-win32 - (ignore-errors - (with-open-file (r "/dev/urandom" :element-type '(unsigned-byte 32) - :direction :input :if-does-not-exist :error) - (let ((a (make-array '(8) :element-type '(unsigned-byte 32)))) - (assert (= 8 (read-sequence a r))) - a))) - ;; When /dev/urandom is not available, we make do with time and pid - ;; Thread ID and/or address of a CONS cell would be even better, but... - (progn - (/show0 "No /dev/urandom, using randomness from time and pid") - (+ (get-internal-real-time) - #!+unix (ash (sb!unix:unix-getpid) 32)))))) + (seed-random-state (os-random-seed))) ;; For convenience to users, we accept (simple-array (unsigned-byte 8) (*)) ;; We just convert it to (simple-array (unsigned-byte 32) (*)) in a ;; completely straightforward way.