lua-arc4random

Cryptographically secure PRNG for Lua
Log | Files | Refs | README

main.c (2688B)


      1 /*
      2  * Copyright (c) 2015, Michael Savage <mike@mikejsavage.co.uk>
      3  *
      4  * Permission to use, copy, modify, and/or distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 */
     16 
     17 #include <stdlib.h>
     18 #include <stdint.h>
     19 #include <math.h>
     20 
     21 #include <lua.h>
     22 #include <lualib.h>
     23 #include <lauxlib.h>
     24 
     25 #if LUA_VERSION_NUM < 502
     26 	#define luaL_newlib( L, l ) ( lua_newtable( L ), luaL_register( L, NULL, l ) )
     27 #endif
     28 
     29 #define LUAINT_MAX ( sizeof( lua_Integer ) == 4 ? INT32_MAX : INT64_MAX )
     30 
     31 static int luaarc4_random( lua_State * const L ) {
     32 	if( lua_gettop( L ) == 0 ) {
     33 		// generate a random 53 bit int, then divide by 2^53
     34 		const uint64_t r64 = ( ( uint64_t ) arc4random() << 32 ) | arc4random();
     35 		const uint64_t r53 = r64 & ( ( UINT64_C( 1 ) << 53 ) - 1 );
     36 		const double d = ( double ) r53 / ( UINT64_C( 1 ) << 53 );
     37 
     38 		lua_pushnumber( L, d );
     39 
     40 		return 1;
     41 	}
     42 
     43 	lua_Integer min = 1;
     44 	lua_Integer max;
     45 
     46 	if( lua_gettop( L ) == 1 ) {
     47 		max = lua_tointeger( L, 1 );
     48 	}
     49 	else {
     50 		min = lua_tointeger( L, 1 );
     51 		max = lua_tointeger( L, 2 );
     52 	}
     53 
     54 	if( max == LUAINT_MAX ) {
     55 		lua_pushliteral( L, "upper bound too large" );
     56 		return lua_error( L );
     57 	}
     58 
     59 	lua_Integer max_plus_one = max + 1;
     60 
     61 	if( max_plus_one <= min ) {
     62 		lua_pushliteral( L, "interval is empty" );
     63 		return lua_error( L );
     64 	}
     65 
     66 	if( max_plus_one - min > UINT32_MAX ) {
     67 		lua_pushliteral( L, "interval too large" );
     68 		return lua_error( L );
     69 	}
     70 
     71 	const lua_Integer r = min + arc4random_uniform( max_plus_one - min );
     72 	lua_pushinteger( L, r );
     73 
     74 	return 1;
     75 }
     76 
     77 static int luaarc4_buf( lua_State * const L ) {
     78 	const long bytes = luaL_checkinteger( L, 1 );
     79 	char * const buf = malloc( bytes );
     80 
     81 	if( buf == NULL ) {
     82 		lua_pushliteral( L, "out of memory" );
     83 		return lua_error( L );
     84 	}
     85 
     86 	arc4random_buf( buf, bytes );
     87 	lua_pushlstring( L, buf, bytes );
     88 	free( buf );
     89 
     90 	return 1;
     91 }
     92 
     93 static const struct luaL_Reg luaarc4_lib[] = {
     94 	{ "random", luaarc4_random },
     95 	{ "buf", luaarc4_buf },
     96 	{ NULL, NULL },
     97 };
     98 
     99 LUALIB_API int luaopen_arc4random( lua_State * const L ) {
    100 	luaL_newlib( L, luaarc4_lib );
    101 
    102 	return 1;
    103 }