Skip to content

Instantly share code, notes, and snippets.

@starwing
Last active October 19, 2021 02:12
Show Gist options
  • Save starwing/4d27dc97bc87c90214e2b6af2b3ff4af to your computer and use it in GitHub Desktop.
Save starwing/4d27dc97bc87c90214e2b6af2b3ff4af to your computer and use it in GitHub Desktop.
Base58 encoding in Lua.
#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