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) { |
