Base32

object Base32

RFC 4648 base32 encode/decode. Pure Kotlin (no platform codecs), so it works in commonMain across every target.

Port of libtorrent's base32decode / base32encode_i2p (src/escape_string.cpp). In BitTorrent, base32 shows up in two places:

  • v1 magnet links historically allowed the 20-byte info-hash to be encoded as a 32-character base32 string ("xt=urn:btih:" followed by base32), and v2 magnet links / well-known network identifiers also use base32.

  • i2p addresses use a non-standard lowercase variant of base32.

Two important fidelity notes about the libtorrent source this is ported from:

  1. libtorrent's encode equivalent only exists as base32encode_i2p, which uses the lowercase alphabet a-z2-7 and emits no padding (i2p convention). RFC 4648, which is what v2 magnet links and most of the world expect, uses the uppercase alphabet A-Z2-7 and pads the final group to a multiple of 8 characters with =. This object implements the RFC 4648 behaviour (uppercase + padding). It reuses the exact same bit-packing as base32encode_i2p; only the alphabet table and the trailing = padding differ. See encodeI2p for the verbatim i2p behaviour.

  2. libtorrent's base32decode is already standard-alphabet (A-Z2-7) and is deliberately lenient: it upper-cases input first (so lowercase decodes too), and it maps the ambiguous digit '1' to the letter 'I'. Both quirks are preserved here. On any other unexpected character it returns an empty result, exactly like the C++ (which returns std::string()); decodeOrNull surfaces that as null while decode returns an empty array, matching the C++ return.

Functions

Link copied to clipboard

Decode an RFC 4648 base32 s to bytes. Returns an empty array on any invalid character, mirroring libtorrent's base32decode returning std::string().

Link copied to clipboard

Like decode, but returns null (instead of an empty array) when the input contains a character outside the base32 alphabet, so callers can distinguish "decoded to nothing" from "malformed".

Link copied to clipboard
fun encode(bytes: ByteArray, offset: Int = 0, length: Int = bytes.size - offset): String

Encode bytes to an RFC 4648 base32 string (uppercase, =-padded).

Link copied to clipboard
fun encodeI2p(bytes: ByteArray, offset: Int = 0, length: Int = bytes.size - offset): String

Encode bytes using i2p's lowercase, unpadded base32 alphabet: the exact behaviour of libtorrent's base32encode_i2p.