/* * lbn.c * big-number library for Lua 5.1 based on OpenSSL bn * Luiz Henrique de Figueiredo * 11 Nov 2010 22:56:45 * This code is hereby placed in the public domain. */ #include #include #include #include #include #if OPENSSL_VERSION_NUMBER < 0x10100000L #define BN_is_negative(a) ((a)->neg != 0) #endif #include "lua.h" #include "lauxlib.h" #include "lualib.h" #include "private.h" #define lua_boxpointer(L,u) \ (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u)) #define MYNAME "bn" #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2010 / "\ "based on OpenSSL " SHLIB_VERSION_NUMBER #define MYTYPE "openssl.bn" static void error(lua_State *L, const char *message) { luaL_error(L, "(bn) %s %s", message, ERR_reason_error_string(ERR_get_error())); } static BIGNUM *Bnew(lua_State *L) { BIGNUM *x = BN_new(); if (x == NULL) error(L, "BN_new failed"); lua_boxpointer(L, x); luaL_getmetatable(L, MYTYPE); lua_setmetatable(L, -2); return x; } static BIGNUM *Bget(lua_State *L, int i) { switch (lua_type(L, i)) { case LUA_TNUMBER: case LUA_TSTRING: { BIGNUM *x = Bnew(L); const char *s = lua_tostring(L, i); if (s[0] == 'X' || s[0] == 'x') BN_hex2bn(&x, s + 1); else BN_dec2bn(&x, s); lua_replace(L, i); return x; } default: return *((void**)luaL_checkudata(L, i, MYTYPE)); } } static int Bbits(lua_State *L) /** bits(x) */ { BIGNUM *a = Bget(L, 1); lua_pushinteger(L, BN_num_bits(a)); return 1; } static int Btostring(lua_State *L) /** tostring(x) */ { BIGNUM *a = Bget(L, 1); char *s = BN_bn2dec(a); lua_pushstring(L, s); OPENSSL_free(s); return 1; } static int Btohex(lua_State *L) /** tohex(x) */ { BIGNUM *a = Bget(L, 1); char *s = BN_bn2hex(a); lua_pushstring(L, s); OPENSSL_free(s); return 1; } static int Btotext(lua_State *L) /** totext(x) */ { BIGNUM *a = Bget(L, 1); int n = BN_num_bytes(a); void *s = malloc(n); if (s == NULL) return 0; BN_bn2bin(a, s); lua_pushlstring(L, s, n); free(s); return 1; } static int Btonumber(lua_State *L) /** tonumber(x) */ { Btostring(L); lua_pushnumber(L, lua_tonumber(L, -1)); return 1; } static int Biszero(lua_State *L) /** iszero(x) */ { BIGNUM *a = Bget(L, 1); lua_pushboolean(L, BN_is_zero(a)); return 1; } static int Bisone(lua_State *L) /** isone(x) */ { BIGNUM *a = Bget(L, 1); lua_pushboolean(L, BN_is_one(a)); return 1; } static int Bisodd(lua_State *L) /** isodd(x) */ { BIGNUM *a = Bget(L, 1); lua_pushboolean(L, BN_is_odd(a)); return 1; } static int Bisneg(lua_State *L) /** isneg(x) */ { BIGNUM *a = Bget(L, 1); lua_pushboolean(L, BN_is_negative(a)); return 1; } static int Bnumber(lua_State *L) /** number(x) */ { Bget(L, 1); lua_settop(L, 1); return 1; } static int Btext(lua_State *L) /** text(t) */ { size_t l; const char *s = luaL_checklstring(L, 1, &l); BIGNUM *x = Bnew(L); BN_bin2bn((const unsigned char *)s, l, x); return 1; } static int Bcompare(lua_State *L) /** compare(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); lua_pushinteger(L, BN_cmp(a, b)); return 1; } static int Beq(lua_State *L) { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); lua_pushboolean(L, BN_cmp(a, b) == 0); return 1; } static int Blt(lua_State *L) { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); lua_pushboolean(L, BN_cmp(a, b) < 0); return 1; } static int Bsqr(lua_State *L) /** sqr(x) */ { BIGNUM *a = Bget(L, 1); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_sqr(c, a, ctx); BN_CTX_free(ctx); return 1; } static int Bneg(lua_State *L) /** neg(x) */ { BIGNUM *a = BN_new(); BIGNUM *b = Bget(L, 1); BIGNUM *c = Bnew(L); BN_set_word(a, 0); BN_sub(c, a, b); BN_free(a); return 1; } static int Babs(lua_State *L) /** abs(x) */ { BIGNUM *b = Bget(L, 1); if (BN_is_negative(b)) { BIGNUM *a = BN_new(); BIGNUM *c = Bnew(L); BN_set_word(a, 0); BN_sub(c, a, b); BN_free(a); } else lua_settop(L, 1); return 1; } static int Badd(lua_State *L) /** add(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *c = Bnew(L); BN_add(c, a, b); return 1; } static int Bsub(lua_State *L) /** sub(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *c = Bnew(L); BN_sub(c, a, b); return 1; } static int Bmul(lua_State *L) /** mul(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mul(c, a, b, ctx); BN_CTX_free(ctx); return 1; } static int Bdiv(lua_State *L) /** div(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *q = Bnew(L); BIGNUM *r = NULL; BN_CTX *ctx = BN_CTX_new(); BN_div(q, r, a, b, ctx); BN_CTX_free(ctx); return 1; } static int Bmod(lua_State *L) /** mod(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *q = NULL; BIGNUM *r = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_div(q, r, a, b, ctx); BN_CTX_free(ctx); return 1; } static int Brmod(lua_State *L) /** rmod(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *r = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_nnmod(r, a, b, ctx); BN_CTX_free(ctx); return 1; } static int Bdivmod(lua_State *L) /** divmod(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *q = Bnew(L); BIGNUM *r = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_div(q, r, a, b, ctx); BN_CTX_free(ctx); return 2; } static int Bgcd(lua_State *L) /** gcd(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_gcd(c, a, b, ctx); BN_CTX_free(ctx); return 1; } static int Bpow(lua_State *L) /** pow(x,y) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_exp(c, a, b, ctx); BN_CTX_free(ctx); return 1; } static int Baddmod(lua_State *L) /** addmod(x,y,m) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *m = Bget(L, 3); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mod_add(c, a, b, m, ctx); BN_CTX_free(ctx); return 1; } static int Bsubmod(lua_State *L) /** submod(x,y,m) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *m = Bget(L, 3); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mod_sub(c, a, b, m, ctx); BN_CTX_free(ctx); return 1; } static int Bmulmod(lua_State *L) /** mulmod(x,y,m) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *m = Bget(L, 3); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mod_mul(c, a, b, m, ctx); BN_CTX_free(ctx); return 1; } static int Bpowmod(lua_State *L) /** powmod(x,y,m) */ { BIGNUM *a = Bget(L, 1); BIGNUM *b = Bget(L, 2); BIGNUM *m = Bget(L, 3); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(c, a, b, m, ctx); BN_CTX_free(ctx); return 1; } static int Bsqrmod(lua_State *L) /** sqrmod(x) */ { BIGNUM *a = Bget(L, 1); BIGNUM *m = Bget(L, 2); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mod_sqr(c, a, m, ctx); BN_CTX_free(ctx); return 1; } static int Binvmod(lua_State *L) /** invmod(x) */ { BIGNUM *a = Bget(L, 1); BIGNUM *m = Bget(L, 2); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mod_inverse(c, a, m, ctx); BN_CTX_free(ctx); return 1; } static int Bsqrtmod(lua_State *L) /** sqrtmod(x) */ { BIGNUM *a = Bget(L, 1); BIGNUM *m = Bget(L, 2); BIGNUM *c = Bnew(L); BN_CTX *ctx = BN_CTX_new(); BN_mod_sqrt(c, a, m, ctx); BN_CTX_free(ctx); return 1; } static int Brandom(lua_State *L) /** random(bits) */ { int bits = luaL_optint(L, 1, 32); BIGNUM *x = Bnew(L); BN_rand(x, bits, -1, 0); return 1; } static int Baprime(lua_State *L) /** aprime(bits) */ { int bits = luaL_optint(L, 1, 32); BIGNUM *x = Bnew(L); if (BN_generate_prime_ex(x, bits, 0, NULL, NULL, NULL)) return 1; else lua_pop(L, 1); return 0; } static int Bisprime(lua_State *L) /** isprime(x,[checks]) */ { int checks = luaL_optint(L, 2, BN_prime_checks); BIGNUM *a = Bget(L, 1); BN_CTX *ctx = BN_CTX_new(); lua_pushboolean(L, BN_is_prime_fasttest_ex(a, checks, ctx, 1, NULL)); BN_CTX_free(ctx); return 1; } static int Bgc(lua_State *L) { BIGNUM *a = Bget(L, 1); BN_free(a); return 0; } static const luaL_Reg R[] = { { "__add", Badd }, /** __add(x,y) */ { "__div", Bdiv }, /** __div(x,y) */ { "__eq", Beq }, /** __eq(x,y) */ { "__gc", Bgc }, { "__lt", Blt }, /** __lt(x,y) */ { "__mod", Bmod }, /** __mod(x,y) */ { "__mul", Bmul }, /** __mul(x,y) */ { "__pow", Bpow }, /** __pow(x,y) */ { "__sub", Bsub }, /** __sub(x,y) */ { "__tostring", Btostring}, /** __tostring(x) */ { "__unm", Bneg }, /** __unm(x) */ { "abs", Babs }, { "add", Badd }, { "addmod", Baddmod }, { "aprime", Baprime }, { "bits", Bbits }, { "compare", Bcompare}, { "div", Bdiv }, { "divmod", Bdivmod }, { "gcd", Bgcd }, { "invmod", Binvmod }, { "isneg", Bisneg }, { "isodd", Bisodd }, { "isone", Bisone }, { "isprime", Bisprime}, { "iszero", Biszero }, { "mod", Bmod }, { "mul", Bmul }, { "mulmod", Bmulmod }, { "neg", Bneg }, { "number", Bnumber }, { "pow", Bpow }, { "powmod", Bpowmod }, { "random", Brandom }, { "rmod", Brmod }, { "sqr", Bsqr }, { "sqrmod", Bsqrmod }, { "sqrtmod", Bsqrtmod}, { "sub", Bsub }, { "submod", Bsubmod }, { "text", Btext }, { "tohex", Btohex }, { "totext", Btotext }, { "tonumber", Btonumber}, { "tostring", Btostring}, { NULL, NULL } }; int luaopen_bn(lua_State *L) { ERR_load_BN_strings(); RAND_seed(MYVERSION, sizeof(MYVERSION)); luaL_newmetatable(L, MYTYPE); luaL_setfuncs(L, R, 0); lua_pushliteral(L, "version"); /** version */ lua_pushliteral(L, MYVERSION); lua_settable(L, -3); lua_pushliteral(L, "__index"); lua_pushvalue(L, -2); lua_settable(L, -3); return 1; }