CrockfordBase32
Crockford Base32 encoding and decoding for integers and bitstrings in Elixir. It supports non-negative integers, arbitrary bitstrings, optional check symbols, and fixed-width encoders.
See Crockford's Base32 specification for the format.
Installation
def deps do
[
{:crockford_base32, "~> 0.9"}
]
end
Quick start
iex> CrockfordBase32.encode(1234)
"16J"
iex> CrockfordBase32.encode("abc", checksum: true, split_size: 3)
"C5H-66C"
iex> CrockfordBase32.decode_to_integer("16-j")
{:ok, 1234}
iex> CrockfordBase32.decode_to_bitstring("C5H66C", checksum: true)
{:ok, "abc"}
iex> CrockfordBase32.encode(<<5::size(3)>>)
"M"
Options and decoding
checksum: trueappends a Crockford check symbol when encoding. Pass the same option when decoding to require and validate the final symbol.split_sizeinserts hyphens between groups when encoding. Decoders ignore hyphens.- Default decoding is case-insensitive;
IandLdecode as1, andOdecodes as0. - Invalid input returns
:error; a failed check symbol returns:error_checksum.
The default output alphabet is 0123456789ABCDEFGHJKMNPQRSTVWXYZ. Check
symbols additionally use *~$=U.
Fixed-width encoding
Generate fixed-width encode/1 and decode/1 functions when the input has a
known bit width. decode/1 always returns a bitstring with the configured
width.
type: :bitstringis the default and accepts only a bitstring with the configured size.type: :integeralso accepts a non-negative integer. Validate the integer range in your application when fixed-width truncation would be unacceptable.
ULID: a 128-bit integer
A ULID combines a 48-bit Unix timestamp in
milliseconds with 80 bits of randomness. Use type: :integer to preserve the
numeric leading-zero padding required by its 26-character representation.
defmodule MyApp.ULID.Base32 do
use CrockfordBase32,
bits_size: 128,
type: :integer
end
timestamp_ms = 1_648_103_085_000
randomness = <<0::size(80)>>
ulid = <<timestamp_ms::unsigned-size(48), randomness::bitstring>>
encoded = MyApp.ULID.Base32.encode(ulid)
# "01FYX9JMY80000000000000000"
{:ok, ^ulid} = MyApp.ULID.Base32.decode(encoded)
TypeID: a 130-bit bitstring
A TypeID suffix is 26 lowercase Base32 symbols. It represents two leading zero bits followed by a 128-bit UUID, so use a fixed-width bitstring codec with TypeID's lowercase alphabet:
defmodule MyApp.TypeID.Base32 do
use CrockfordBase32,
bits_size: 130,
alphabet: ~c"0123456789abcdefghjkmnpqrstvwxyz"
end
The variable-length decoder cannot infer this 130-bit width and returns 128 bits for the sample suffix. The fixed-width decoder preserves all 130 bits:
suffix = "01hy3b3hq5fmevjn8me7c4hzdm"
{:ok, variable_width} = CrockfordBase32.decode_to_bitstring(suffix)
bit_size(variable_width)
# 128
{:ok, type_id} = MyApp.TypeID.Base32.decode(suffix)
bit_size(type_id)
# 130
MyApp.TypeID.Base32.encode(type_id)
# "01hy3b3hq5fmevjn8me7c4hzdm"
Credits
Thanks to these implementations and references: