Skip to content

Instantly share code, notes, and snippets.

@Ishotihadus
Last active April 21, 2022 03:26
Show Gist options
  • Save Ishotihadus/9ac149d3fddf89ca1c504286e0bf8a58 to your computer and use it in GitHub Desktop.
Save Ishotihadus/9ac149d3fddf89ca1c504286e0bf8a58 to your computer and use it in GitHub Desktop.
Fast Base32 Implementation in Pure Ruby
module Base32
TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
TABLE_REVERSE = Array.new(256)
TABLE.each_byte.with_index{|c, i| TABLE_REVERSE[c.ord] = i}
TABLE_REVERSE.freeze
PADDING = [0, 0, 0, 0, 0].pack('C*').freeze
def self.encode32(str, padding: false)
bytes = String.new(str, encoding: Encoding::ASCII_8BIT)
bytesize = bytes.bytesize
bytes << PADDING
chunksize = (bytesize + 4) / 5
ret = String.new(capacity: chunksize * 8)
chunksize.times do |i|
s = i * 5
b1 = bytes[s].ord
b2 = bytes[s + 1].ord
b3 = bytes[s + 2].ord
b4 = bytes[s + 3].ord
b5 = bytes[s + 4].ord
ret << TABLE[b1 >> 3]
ret << TABLE[b1 << 2 & 0x1c | b2 >> 6]
ret << TABLE[b2 >> 1 & 0x1f]
ret << TABLE[b2 << 4 & 0x10 | b3 >> 4]
ret << TABLE[b3 << 1 & 0x1e | b4 >> 7]
ret << TABLE[b4 >> 2 & 0x1f]
ret << TABLE[b4 << 3 & 0x18 | b5 >> 5]
ret << TABLE[b5 & 0x1f]
end
if padding
(((bytesize * 8 + 4) / 5)...(ret.size)).each do |i|
ret[i] = '='
end
ret
else
ret[0, (bytesize * 8 + 4) / 5]
end
end
def self.decode32(str)
ret = String.new(capacity: (str.bytesize * 5 + 3) / 8)
current = 0
pos = 0
str.each_byte do |b|
c = TABLE_REVERSE[b]
break unless c
case pos
when 0
current = c << 3
pos = 5
when 1, 2
current |= c << (3 - pos)
pos += 5
when 3
current |= c
ret << current.ord
pos = 0
else
current |= c >> (pos - 3)
ret << current.ord
current = (c << (11 - pos)) & 0xff
pos -= 3
end
end
ret
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment