--- Base-to-base converter by Pierre 'catwell' Chapuis --- MIT licensed (see LICENSE.txt) local letters = "abcdefghijklmnopqrstuvwxyz" local figures = "0123456789" local ascii = {}; for i=1,256 do ascii[i] = i-1 end local unpack = table.unpack or unpack local fmt = string.format local ALPHABET_B62 = figures .. letters .. letters:upper() local ALPHABET_B64 = letters:upper() .. letters .. figures .. "+/" local ALPHABET_B64URL = ALPHABET_B64:sub(1,62) .. "-_" local ALPHABET_B256 = string.char(unpack(ascii)) local _iszero = function(B) if B.iszero then return B.iszero end assert(B.__eq) return function(x) return B.__eq(x, 0) end end local to_bignum = function(self, source) assert(type(source) == "string") local B = self.bignum local s = B.number(0) local m = B.number(1) local b = B.number(self.base) local n for i=#source,1,-1 do n = self.value[source:byte(i)] s = B.add(s, B.mul(n, m)) m = B.mul(m, b) end return s end local from_bignum = function(self, n) local B = self.bignum if type(n) == "number" then n = B.number(n) end local iszero = _iszero(B) local div = assert(B.idiv or B.div) local b = self.base local r = {} while not iszero(n) do r[#r+1] = self.alphabet:byte(B.tonumber(B.mod(n, b)) + 1) n = div(n, b) end return string.char(unpack(r)):reverse() end local methods = { to_bignum = to_bignum, from_bignum = from_bignum, } local converter = function(alphabet, bignum) local r = { bignum = bignum or (require "bc"), alphabet = alphabet, base = #alphabet, value = {}, } for i=1,r.base do r.value[r.alphabet:byte(i)] = i-1 end return setmetatable(r, {__index = methods}) end local _converter = function(alphabet) return function(bignum) return converter(alphabet, bignum) end end local _byte_to_hex = function(x) return fmt("%02x", x:byte()) end local to_hex = function(s) return (s:gsub("(.)", _byte_to_hex)) end local _byte_from_hex = function(x) return string.char(tonumber(x, 16)) end local from_hex = function(s) return (s:gsub("(..)", _byte_from_hex)) end return { converter = converter, base62 = _converter(ALPHABET_B62), base36 = _converter(ALPHABET_B62:sub(1,36)), base10 = _converter(ALPHABET_B62:sub(1,10)), base16 = _converter(ALPHABET_B62:sub(1,16)), base64 = _converter(ALPHABET_B64), base64url = _converter(ALPHABET_B64URL), base256 = _converter(ALPHABET_B256), to_hex = to_hex, from_hex = from_hex, }