This library provides a secure pseudo-random number generator for Common Lisp.
It uses OpenSSL underneath.
It is similar to builtin random function, but can’t be used as a drop-in replacement, because behaviour is slightly different for float numbers.
Builtin CL’s random function reckons float interval as contiguous. But secure-random returns discrete values, coercing integers to floats:
;; Integers
POFTHEDAY> (random 10)
2 (2 bits, #x2, #o2, #b10)
POFTHEDAY> (random 10)
9 (4 bits, #x9, #o11, #b1001)
POFTHEDAY> (secure-random:number 10)
9 (4 bits, #x9, #o11, #b1001)
POFTHEDAY> (secure-random:number 10)
5 (3 bits, #x5, #o5, #b101)
;; Floats
POFTHEDAY> (random 10.0)
2.9430425
POFTHEDAY> (random 10.0)
1.8096626 (180.96626%)
POFTHEDAY> (secure-random:number 10.0)
4.0
POFTHEDAY> (secure-random:number 10.0)
5.0
By the way, did you know that standard randomizer should be initialized each time at program start to get really random results?
The most implementation keeps a compiled in random state in it, and without additional initialization ‘random’ function will give you the same sequence of integers.
Here is the illustration:
$ ros run -L sbcl-bin -e '(princ (random 100))'
5
$ ros run -L sbcl-bin -e '(princ (random 100))'
5
$ ros run -L ccl-bin -e '(princ (random 100))'
75
$ ros run -L ccl-bin -e '(princ (random 100))'
75
$ ros run -L clisp -e '(princ (random 100))'
70
$ ros run -L clisp -e '(princ (random 100))'
70
$ ros run -L ecl -e '(princ (random 100))'
10
$ ros run -L ecl -e '(princ (random 100))'
79
$ ros run -L ecl -e '(princ (random 100))'
13
$ ros run -L ecl -e '(princ (random 100))'
42
As you can see, SBCL, CCL and CLISP have this problem, but ECL - doesn’t.
You can solve the problem by initialization of the random seed:
$ ros run -L sbcl-bin -e '(setf *random-state* (make-random-state t))' \
-e '(princ (random 100))'
68
$ ros run -L sbcl-bin -e '(setf *random-state* (make-random-state t))' \
-e '(princ (random 100))'
99
$ ros run -L ccl-bin -e '(setf *random-state* (make-random-state t))' \
-e '(princ (random 100))'
80
$ ros run -L ccl-bin -e '(setf *random-state* (make-random-state t))' \
-e '(princ (random 100))'
53
$ ros run -L clisp -e '(setf *random-state* (make-random-state t))' \
-e '(princ (random 100))'
68
$ ros run -L clisp -e '(setf *random-state* (make-random-state t))' \
-e '(princ (random 100))'
9
Library ‘secure-random’ does not have this problem:
$ ros run -L sbcl-bin -e '(asdf:load-system :secure-random)' \
-e '(princ (secure-random:number 100))'
30
$ ros run -L sbcl-bin -e '(asdf:load-system :secure-random)' \
-e '(princ (secure-random:number 100))'
16
$ ros run -L sbcl-bin -e '(asdf:load-system :secure-random)' \
-e '(princ (secure-random:number 100))'
37
$ ros run -L sbcl-bin -e '(asdf:load-system :secure-random)' \
-e '(princ (secure-random:number 100))'
4
$ ros run -L sbcl-bin -e '(asdf:load-system :secure-random)' \
-e '(princ (secure-random:number 100))'
62