Сравнительная таблица
Все эти кодировки превращают произвольные байты в печатный текст и обратно без потерь. Различаются они количеством символов, самими символами и тем, насколько вырастает результат.
| Кодировка | Алфавит | Размер результата | Регистр важен | Безопасна для URL | Где применяется |
|---|---|---|---|---|---|
| Hex (Base16) | 0-9 a-f | 200% | Нет | Да | Хеши, MAC-адреса, дампы байтов, коды цветов |
| Base32 (RFC 4648) | A-Z 2-7, дополнение = | 160% | Нет (по спецификации заглавные) | Да, без = | Секреты TOTP, onion-адреса Tor, DNSSEC (base32hex) |
| Base58 (Bitcoin) | 1-9 A-Z a-z без 0 O I l | около 137% | Да | Да | Адреса Bitcoin, IPFS CIDv0 (Qm…), ключи Solana |
| Base64 | A-Z a-z 0-9 + /, дополнение = | 133% | Да | Нет | Почтовые вложения, data URI, PEM, данные в JSON |
| Base64URL | A-Z a-z 0-9 - _ | 133% | Да | Да | JWT, токены в URL, имена файлов |
| Ascii85 | от ! до u, плюс z | 125% | Да | Нет | Потоки PDF и PostScript |
| Z85 | 85 символов, включая .-:+=^!/*?&<>()[]{}@%$# | 125% | Да | Нет | Ключи CURVE в ZeroMQ |
| Base45 (RFC 9285) | 0-9 A-Z, пробел, $%*+-./: | 150% | Нет (только заглавные) | Нет | QR-коды, EU Digital COVID Certificate |
«Размер результата» означает длину закодированных данных в процентах от длины исходных для больших объёмов. Base64 тратит 4 символа на 3 байта, Base32 – 8 на 5, Base85 – 5 на 4, Base45 – 3 на 2. У Base58 нет фиксированного блока, поэтому его коэффициент равен log(256) / log(58), примерно 1,366. Точные цифры для конкретного ввода сразу по всем кодировкам показывает калькулятор размера.
Один и тот же ввод в каждой кодировке
Вот 12-байтная ASCII-строка Hello world!, закодированная девятью способами. Двенадцать кратно и 3, и 4, поэтому Base64 и вариантам Base85 дополнение не нужно.
| Кодировка | Результат | Длина |
|---|---|---|
| Hex | 48656c6c6f20776f726c6421 | 24 |
| Base32 | JBSWY3DPEB3W64TMMQQQ==== | 24 (20 без дополнения) |
| Base32hex | 91IMOR3F41RMUSJCCGGG==== | 24 |
| Base58 (алфавит Bitcoin) | 2NEpo7TZRhna7vSvL | 17 |
| Base64 | SGVsbG8gd29ybGQh | 16 |
| Base45 | %69 VD82EK4F.KESTC | 18 |
| Ascii85 | 87cURD]j7BEbo80 | 15 |
| Z85 | nm=QNzY<mxA+]nf | 15 |
| Base85 (RFC 1924 / git) | NM&qnZy<MXa%^NF | 15 |
Base64URL здесь совпадает с Base64, потому что в результате нет + и /. Разница проявляется только на определённых байтах: fb ef be в Base64 даёт ++++, а в Base64URL ----.
Стандартная библиотека Python покрывает большую часть таблицы. z85encode появился в Python 3.13:
import base64
data = b"Hello world!"
print(data.hex()) # 48656c6c6f20776f726c6421
print(base64.b32encode(data).decode()) # JBSWY3DPEB3W64TMMQQQ====
print(base64.b64encode(data).decode()) # SGVsbG8gd29ybGQh
print(base64.a85encode(data).decode()) # 87cURD]j7BEbo80
print(base64.b85encode(data).decode()) # NM&qnZy<MXa%^NF
print(base64.z85encode(data).decode()) # nm=QNzY<mxA+]nf
Base58 в стандартной библиотеке нет, но он укладывается в несколько строк, потому что это обычный перевод одного большого целого числа в другую систему счисления:
B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
def b58encode(data: bytes) -> str:
n = int.from_bytes(data, "big")
out = ""
while n:
n, r = divmod(n, 58)
out = B58[r] + out
zeros = len(data) - len(data.lstrip(b"\0"))
return "1" * zeros + out
print(b58encode(b"Hello world!")) # 2NEpo7TZRhna7vSvL
print(b58encode(b"\0\0\x01")) # 112
Каждый ведущий нулевой байт превращается в литерал 1, потому что большое целое число не может запомнить ведущие нули. Поэтому все классические адреса Bitcoin с нулевым байтом версии начинаются с 1.
Где применяется каждая кодировка
Hex
Hex тратит по два символа на байт, поэтому из всех вариантов он самый объёмный и самый читаемый. Каждый символ соответствует ровно 4 битам, так что байт со смещением n всегда занимает символы 2n и 2n+1. Именно поэтому хеши, контрольные суммы и отладочные дампы почти всегда пишут в hex. Декодеры принимают и DEADBEEF, и deadbeef. Конвертировать помогут Base64 в hex и hex в Base64.
Base32
Base32 использует только заглавные буквы и цифры от 2 до 7. Он выживает в системах, которые не различают регистр (доменные имена, некоторые файловые системы, люди, вводящие код в телефон), и обходится без 0, 1 и 8, похожих на O, I и B. Приложения-аутентификаторы хранят секреты TOTP в Base32, а onion-адреса Tor v3 состоят из 56 строчных символов Base32. RFC 4648 определяет и base32hex (0-9 A-V), который сохраняет порядок сортировки исходных байтов. Попробуйте кодировщик Base32.
Base58
Base58 появился вместе с Bitcoin. В нём нет 0, O, I и l (их легко спутать), а также + и / (они ломают выделение двойным щелчком и URL). Адреса Bitcoin добавляют сверху байт версии и 4-байтную контрольную сумму; такой формат называется Base58Check. Хеши IPFS CIDv0 тоже записаны в Base58; они начинаются с байтов multihash 12 20, поэтому в Base58 всегда начинаются с Qm. Весь ввод обрабатывается как одно число, поэтому время конвертации растёт квадратично с длиной, и Base58 используют для ключей и хешей, а не для файлов. Попробуйте кодировщик Base58.
Ascii85, Z85 и Base85 из git
Семейство Base85 упаковывает 4 байта в 5 символов, это самая плотная из широко поддерживаемых кодировок. Подвох в алфавите: среди 85 печатных символов, смотря по варианту, есть кавычки, обратная косая черта, <, > или &.
- Ascii85 (Adobe) использует символы от
!доu, обрамляет результат в<~и~>и записывает четыре нулевых байта одним символомz. Его используют PostScript и PDF (фильтрASCII85Decode). - Z85 (ZeroMQ) берёт символы, безопасные внутри строковых литералов C и JSON, без кавычек и обратной косой черты. Длина ввода должна быть кратна 4. 32-байтный ключ CURVE занимает 40 символов.
- Base85 по RFC 1924 был первоапрельским предложением для записи адресов IPv6. Его алфавит живёт в бинарных патчах git и в
b85encodeиз Python.
Инструмент Base85 работает со всеми тремя; у Z85 есть отдельная страница.
Base45
Base45 создан для QR-кодов. Алфавитно-цифровой режим QR-кода хранит ровно 45 символов (цифры, заглавные буквы, пробел и $%*+-./:) по 5,5 бита на символ, тогда как в байтовом режиме на символ уходит 8 бит. Base45 превращает 2 байта в 3 таких символа, что внутри QR-кода обходится примерно в 3%. Текст Base64 вынужден использовать байтовый режим, и рост составляет 33%. EU Digital COVID Certificate использовал Base45 именно поэтому. Попробуйте кодировщик Base45.
Как выбрать
Берите ту кодировку, которую ждёт принимающая сторона. Библиотеке JWT нужен Base64URL, приложению-аутентификатору Base32, Bitcoin-кошельку Base58Check. Если обе стороны под вашим контролем, работают такие эмпирические правила:
- Байты внутри JSON, XML, письма или тела HTTP: Base64. В каждом языке есть быстрая встроенная реализация, а рост на 33% приемлем.
- Внутри URL, cookie или имени файла: Base64URL без дополнения.
- Значение будут читать, набирать или сравнивать люди: hex для коротких хешей, Base32, если регистр может потеряться, Base58, если результат должен выглядеть компактно и не содержать похожих символов.
- Важен каждый байт, а декодер ваш: Z85 или Ascii85.
- QR-коды: Base45.
Компромисс всегда один и тот же: чем больше алфавит, тем короче результат и тем больше символов, которые где-нибудь придётся экранировать. Почему Base64 вырастает на треть, объясняет статья о росте размера в Base64. URL-safe вариант разобран в статье Base64 и Base64URL.
Вопросы и ответы
Какая кодировка двоичных данных в текст самая компактная?
Из распространённых самая компактная Base85 (Ascii85 и Z85) с ростом на 25%, следом идёт Base64 с 33%. basE91 может чуть лучше, но поддерживается редко. Если он нужен, есть инструмент Base91.
Почему в Bitcoin Base58, а не Base64?
В Base58 нет 0, O, I, l, + и /, поэтому адрес проще прочитать вслух, переписать вручную и выделить двойным щелчком в текстовом поле. Платой становится медленное преобразование большого числа, но для 25-байтных адресов это неважно.
Важен ли регистр в Base32 и Base58?
Алфавит RFC 4648 состоит из заглавных букв, и строгие декодеры отклоняют строчные. Многие принимают оба регистра; в Python для этого нужен casefold=True. Base58 чувствителен к регистру: a и A в нём разные цифры. Hex практически во всех декодерах регистронезависим.
Можно ли напрямую перевести Base64 в Base58 или Base32?
Да: декодировать в байты и закодировать заново. Конвертеры Base64 в Base58 и Base64 в Base32 делают оба шага локально в браузере.