Last active
October 19, 2021 02:12
-
-
Save starwing/4d27dc97bc87c90214e2b6af2b3ff4af to your computer and use it in GitHub Desktop.
Base58 encoding in Lua.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define LUA_LIB | |
#include <lua.h> | |
#include <lauxlib.h> | |
#include <assert.h> | |
#include <string.h> | |
static size_t b58_posrelatI(lua_Integer pos, size_t len) { | |
if (pos > 0) | |
return (size_t)pos; | |
else if (pos == 0) | |
return 1; | |
else if (pos < -(lua_Integer)len) | |
return 1; | |
else return len + (size_t)pos + 1; | |
} | |
static size_t b58_getendpos(lua_State *L, int arg, lua_Integer def, size_t len) { | |
lua_Integer pos = luaL_optinteger(L, arg, def); | |
if (pos > (lua_Integer)len) | |
return len; | |
else if (pos >= 0) | |
return (size_t)pos; | |
else if (pos < -(lua_Integer)len) | |
return 0; | |
else return len + (size_t)pos + 1; | |
} | |
static const char *b58_checklstring(lua_State *L, int idx, size_t *plen) { | |
size_t l; | |
const char *s = luaL_checklstring(L, idx, &l); | |
size_t start = b58_posrelatI(luaL_optinteger(L, idx+1, 1), l); | |
size_t end = b58_getendpos(L, idx+2, -1, l); | |
if (start <= end) { | |
*plen = end - start + 1; | |
return s + start - 1; | |
} | |
*plen = 0; | |
return ""; | |
} | |
static char b58_enctbl[58]; | |
static char b58_dectbl[256]; | |
static int Lsettable(lua_State *L) { | |
size_t i, len; | |
const char *tbl = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
const char *s = luaL_optlstring(L, 1, tbl, &len); | |
if (len != 58) return luaL_argerror(L, 1, "length invalid"); | |
memcpy(b58_enctbl, s, len); | |
memset(b58_dectbl, 0xFF, 256); | |
for (i = 0; i < len; ++i) | |
b58_dectbl[s[i] & 0xFF] = i; | |
return 0; | |
} | |
static int Lencode(lua_State *L) { | |
size_t len, buflen = 0; | |
const char *s = b58_checklstring(L, 1, &len), *e = s + len; | |
size_t i, j, carry, size = len * 138 / 100 + 1; | |
char *buf; | |
luaL_Buffer B; | |
luaL_buffinit(L, &B); | |
for (; s < e && *s == 0; ++s, --len) | |
luaL_addchar(&B, b58_enctbl[0]); | |
buf = memset(luaL_prepbuffsize(&B, size), 0, size); | |
for (; s < e; ++s) { | |
for (carry = *s, i = 0; (carry != 0 || i < buflen) && i < size; ++i) { | |
carry += buf[size - i - 1] << 8; | |
buf[size - i - 1] = carry % 58; | |
carry /= 58; | |
} | |
assert(carry == 0); | |
buflen = i; | |
} | |
i = size - buflen; | |
while (i < size && buf[i] == 0) | |
++i, --buflen; | |
for (j = 0; i < size; ++i, ++j) | |
buf[j] = b58_enctbl[buf[i] & 0xFF]; | |
luaL_addsize(&B, buflen); | |
luaL_pushresult(&B); | |
return 1; | |
} | |
static int Ldecode(lua_State *L) { | |
size_t len, buflen = 0; | |
const char *s = b58_checklstring(L, 1, &len), *e = s + len; | |
size_t i, carry, size = len * 733 / 1000 + 1; | |
char *buf; | |
luaL_Buffer B; | |
luaL_buffinit(L, &B); | |
for (; s < e && *s == b58_enctbl[0]; ++s, --len) | |
luaL_addchar(&B, 0); | |
buf = memset(luaL_prepbuffsize(&B, size), 0, size); | |
for (; s < e; ++s) { | |
carry = b58_dectbl[*s & 0xFF] & 0xFF; | |
if (carry >= 58) | |
return luaL_error(L, "invalid character '%c' in input", *s); | |
for (i = 0; (carry != 0 || i < buflen) && i < size; ++i) { | |
carry += (buf[size - 1 - i] & 0xFF) * 58; | |
buf[size - 1 - i] = carry & 0xFF; | |
carry >>= 8; | |
} | |
assert(carry == 0); | |
buflen = i; | |
} | |
memmove(buf, buf + size - buflen, buflen); | |
luaL_addsize(&B, buflen); | |
luaL_pushresult(&B); | |
return 1; | |
} | |
LUALIB_API int luaopen_base58(lua_State *L) { | |
luaL_Reg libs[] = { | |
#define ENTRY(name) { #name, L##name } | |
ENTRY(encode), | |
ENTRY(decode), | |
ENTRY(settable), | |
#undef ENTRY | |
{ NULL, NULL } | |
}; | |
lua_pushcfunction(L, Lsettable); | |
lua_call(L, 0, 0); | |
luaL_newlib(L, libs); | |
return 1; | |
} | |
/* cc: flags+='-s -O2 -mdll -DLUA_BUILD_AS_DLL' | |
* cc: libs+='-llua54' output='base58.dll' */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment