diff options
author | William Ahern <william@server.local> | 2013-12-06 19:10:47 -0800 |
---|---|---|
committer | William Ahern <william@server.local> | 2013-12-06 19:10:47 -0800 |
commit | aadabeca7be135fef72758c65fc0eb377e7890b5 (patch) | |
tree | 2d263811c32fe99f09a6d02b35de9201138e79b2 | |
parent | 8226aea35589110a6633077f40fd2c6433dc977d (diff) | |
download | luaossl-aadabeca7be135fef72758c65fc0eb377e7890b5.tar.gz luaossl-aadabeca7be135fef72758c65fc0eb377e7890b5.tar.bz2 luaossl-aadabeca7be135fef72758c65fc0eb377e7890b5.zip |
-n
add uniform number generator to openssl.rand
-rw-r--r-- | openssl.c | 108 |
1 files changed, 105 insertions, 3 deletions
@@ -3790,10 +3790,112 @@ static int rand_ready(lua_State *L) { | |||
3790 | } /* rand_ready() */ | 3790 | } /* rand_ready() */ |
3791 | 3791 | ||
3792 | 3792 | ||
3793 | static 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 | */ | ||
3868 | static 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 | |||
3793 | static const luaL_Reg rand_globals[] = { | 3894 | static 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 | ||
3799 | int luaopen__openssl_rand(lua_State *L) { | 3901 | int luaopen__openssl_rand(lua_State *L) { |