summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Ahern <william@server.local>2013-12-06 19:10:47 -0800
committerWilliam Ahern <william@server.local>2013-12-06 19:10:47 -0800
commitaadabeca7be135fef72758c65fc0eb377e7890b5 (patch)
tree2d263811c32fe99f09a6d02b35de9201138e79b2
parent8226aea35589110a6633077f40fd2c6433dc977d (diff)
downloadluaossl-aadabeca7be135fef72758c65fc0eb377e7890b5.tar.gz
luaossl-aadabeca7be135fef72758c65fc0eb377e7890b5.tar.bz2
luaossl-aadabeca7be135fef72758c65fc0eb377e7890b5.zip
-n
add uniform number generator to openssl.rand
-rw-r--r--openssl.c108
1 files changed, 105 insertions, 3 deletions
diff --git a/openssl.c b/openssl.c
index 5c46d9c..bea15c3 100644
--- a/openssl.c
+++ b/openssl.c
@@ -3790,10 +3790,112 @@ static int rand_ready(lua_State *L) {
3790} /* rand_ready() */ 3790} /* rand_ready() */
3791 3791
3792 3792
3793static unsigned long long rand_llu(lua_State *L) {
3794 unsigned long long llu;
3795
3796 if (!RAND_bytes((void *)&llu, sizeof llu))
3797 throwssl(L, "rand.uniform");
3798
3799 return llu;
3800} /* rand_llu() */
3801
3802/*
3803 * The following algorithm for rand_uniform() is taken from OpenBSD's
3804 * arc4random_uniform, written by Otto Moerbeek, with subsequent
3805 * simplification by Jorden Verwer. Otto's source code comment reads
3806 *
3807 * Uniformity is achieved by generating new random numbers until the one
3808 * returned is outside the range [0, 2**32 % upper_bound). This guarantees
3809 * the selected random number will be inside [2**32 % upper_bound, 2**32)
3810 * which maps back to [0, upper_bound) after reduction modulo upper_bound.
3811 *
3812 * --
3813 * A more bit-efficient approach by the eminent statistician Herman Rubin
3814 * can be found in this sci.crypt Usenet post.
3815 *
3816 * From: hrubin@odds.stat.purdue.edu (Herman Rubin)
3817 * Newsgroups: sci.crypt
3818 * Subject: Re: Generating a random number between 0 and N-1
3819 * Date: 14 Nov 2002 11:20:37 -0500
3820 * Organization: Purdue University Statistics Department
3821 * Lines: 40
3822 * Message-ID: <ar0igl$1ak2@odds.stat.purdue.edu>
3823 * References: <yO%y9.19646$RO1.373975@weber.videotron.net> <3DCD8D75.40408@nospam.com>
3824 * NNTP-Posting-Host: odds.stat.purdue.edu
3825 * X-Trace: mozo.cc.purdue.edu 1037290837 9316 128.210.141.13 (14 Nov 2002 16:20:37 GMT)
3826 * X-Complaints-To: ne...@news.purdue.edu
3827 * NNTP-Posting-Date: Thu, 14 Nov 2002 16:20:37 +0000 (UTC)
3828 * Xref: archiver1.google.com sci.crypt:78935
3829 *
3830 * In article <3DCD8D7...@nospam.com>,
3831 * Michael Amling <nos...@nospam.com> wrote:
3832 * >Carlos Moreno wrote:
3833 *
3834 * I have already posted on this, but a repeat might be
3835 * in order.
3836 *
3837 * If one can trust random bits, the most bitwise efficient
3838 * manner to get a single random integer between 0 and N-1
3839 * can be obtained as follows; the code can be made more
3840 * computationally efficient. I believe it is easier to
3841 * understand with gotos. I am assuming N>1.
3842 *
3843 * i = 0; j = 1;
3844 *
3845 * loop: j=2*j; i=2*i+RANBIT;
3846 * if (j < N) goto loop;
3847 * if (i >= N) {
3848 * i = i - N;
3849 * j = j - N;
3850 * goto loop:}
3851 * else return (i);
3852 *
3853 * The algorithm works because at each stage i is uniform
3854 * between 0 and j-1.
3855 *
3856 * Another possibility is to generate k bits, where 2^k >= N.
3857 * If 2^k = c*N + remainder, generate the appropriate value
3858 * if a k-bit random number is less than c*N.
3859 *
3860 * For N = 17 (numbers just larger than powers of 2 are "bad"),
3861 * the amount of information is about 4.09 bits, the best
3862 * algorithm to generate one random number takes about 5.765
3863 * bits, taking k = 5 uses 9.412 bits, taking k = 6 or 7 uses
3864 * 7.529 bits. These are averages, but the tails are not bad.
3865 *
3866 * (https://groups.google.com/forum/message/raw?msg=sci.crypt/DMslf6tSrD8/rv9rk6oP3r4J)
3867 */
3868static int rand_uniform(lua_State *L) {
3869 if (lua_isnoneornil(L, 1)) {
3870 unsigned long long r = rand_llu(L);
3871
3872 lua_pushnumber(L, r);
3873
3874 return 1;
3875 } else {
3876 unsigned long long N = luaL_checknumber(L, 1);
3877 unsigned long long r, m;
3878
3879 luaL_argcheck(L, N > 1, 1, lua_pushfstring(L, "[0, %d): interval is empty", (int)N));
3880
3881 m = -N % N;
3882
3883 do {
3884 r = rand_llu(L);
3885 } while (r < m);
3886
3887 lua_pushnumber(L, (r % N));
3888
3889 return 1;
3890 }
3891} /* rand_uniform() */
3892
3893
3793static const luaL_Reg rand_globals[] = { 3894static const luaL_Reg rand_globals[] = {
3794 { "bytes", &rand_bytes }, 3895 { "bytes", &rand_bytes },
3795 { "ready", &rand_ready }, 3896 { "ready", &rand_ready },
3796 { NULL, NULL }, 3897 { "uniform", &rand_uniform },
3898 { NULL, NULL },
3797}; 3899};
3798 3900
3799int luaopen__openssl_rand(lua_State *L) { 3901int luaopen__openssl_rand(lua_State *L) {