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 }