RSS Feed

Lisp Project of the Day

secure-random

You can support this project by donating at:

Donate using PatreonDonate using Liberapay

Or see the list of project sponsors.

secure-randomsecurity

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

Brought to you by 40Ants under Creative Commons License