Base58 にエンコードする方法
- 入力 · テキストにテキストを入力するか貼り付けます。入力に合わせて出力 · Base58 に Base58 の文字列が表示されます。
- 出力の下でアルファベットを選びます。Bitcoin(デフォルト。IPFS と Solana でも使われる)、Flickr、Ripple のいずれかです。
- テキストではなく生のバイト列をエンコードするには、変換元を Hex(16進数)か Base64 にして、その形式でバイト列を貼り付けます。公開鍵やハッシュは、ほぼ必ずテキストではなくバイト列です。
- デコードするには、方向の切り替えで Base58 → テキストをクリックするか、バイト列を 16進数で表示する Base58 デコーダーを開きます。
Base58 エンコードの仕組み
Base58 は、Base64 のように入力を固定のビットグループに切り分けません。すべてのバイトをビッグエンディアンの 1 つの大きな数として読み、その数を 58 進数で書き、先頭のゼロバイトごとに 1 を 1 つ加えます。1 バイト変えただけで文字列全体が変わることがあるのも、長さがバイト数だけでなく値によって決まるのもこのためです。
データを 1 つの数として扱うコストはサイズとともに急速に増えるので、このツールは Base58 の入力を 64 KB までに制限しています。どんな鍵、ハッシュ、アドレスにも十分すぎる大きさです。
3 種類の Base58 アルファベット
3 つとも同じ 58 文字(0、O、I、l を除いた数字と英字)を使い、並び順だけが異なります。
| アルファベット | 先頭 | Hello | 0x00 0x00 0x01 |
|---|---|---|---|
| Bitcoin | 123456789ABC… | 9Ajdvzr | 112 |
| Flickr | 123456789abc… | 9aJCVZR | 112 |
| Ripple | rpshnaf39wBU… | 9wjdvzi | rrp |
Flickr は大文字と小文字を入れ替えたもので、Flickr が写真の短縮 URL に使っていました。Ripple のアルファベットは r で始まるので、バージョンバイトがゼロの XRP Ledger のアドレスは、Bitcoin のアドレスが 1 で始まるのと同じように r で始まります。間違ったアルファベットでデコードしても、たいていエラーにならずに別のバイト列が返ってくるので、値が合わないときはまずアルファベットを確認してください。
先頭のゼロと 1 の接頭辞
Base58 はデータを数として扱うので、先頭のゼロバイトは消えてしまいます。この形式は、ゼロバイト 1 つにつき 1 を 1 つ書くことでそれを保持します。
| バイト列(16進数) | Base58 |
|---|---|
00 | 1 |
00 00 | 11 |
00 01 | 12 |
ff | 5Q |
31 × 00 の後に ff | 11111111111111111111111111111115Q |
32 × 00 | 11111111111111111111111111111111 |
最後の行は実在するアドレスです。32 個の 1 は Solana の System Program で、その公開鍵は 32 個のゼロバイトです。先頭のゼロは手書きの Base58 のコードで最も間違えやすい部分で、ゼロを落とすエンコーダーは、デコードするとバイト数が足りない文字列を作ってしまいます。
Base58 が使われる場所
- Bitcoin のアドレスと WIF 鍵。 従来型のアドレス(
1…、3…)と WIF 秘密鍵(5…、K…、L…)は Base58Check、つまりバージョンバイトとチェックサム付きの Base58 です。Bech32 のアドレス(bc1…)は別のエンコーディングです。 - IPFS CIDv0。
Qm…の識別子は、34 バイトのマルチハッシュを素の Base58 にしたものです。12(SHA-256)、20(長さ 32 バイト)とダイジェストからなり、この12 20というヘッダーのおかげで、すべての CIDv0 がQmで始まります。 - Solana。 アドレスと公開鍵は 32 バイトの Base58(32〜44 文字)で、トランザクションの署名は 64 バイトの Base58(最大 88 文字)です。
Python での Base58
Python の標準ライブラリには Base58 がありません。アルゴリズムは書き出せるほど短く、次のバージョンは先頭のゼロも正しく扱います。
ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
def b58encode(data: bytes) -> str:
n = int.from_bytes(data, "big")
out = ""
while n:
n, r = divmod(n, 58)
out = ALPHABET[r] + out
zeros = len(data) - len(data.lstrip(b"\0"))
return "1" * zeros + out
b58encode(b"Hello") # '9Ajdvzr'
b58encode(bytes(32)) # '11111111111111111111111111111111'
本番のコードでは、PyPI の base58 のようなメンテナンスされているパッケージを使えば Base58Check にも対応できます。Python での一般的なエンコードのパターンは Python のページにあります。
よくある質問
Base58 から除かれている文字はどれですか?
Base58 は、Base62 から紛らわしい 4 文字を除いたものです。0(ゼロ)、O(大文字のオー)、I(大文字のアイ)、l(小文字のエル)です。+、/、= もないので、Base58 の文字列はダブルクリックで 1 語として選択でき、エスケープなしで URL に使えます。
Base58 の出力が 1 で始まるのはなぜですか?
1 はそれぞれ、入力の先頭にあるゼロバイト 1 つを表します。素の数ではそうしたゼロが失われるので、Base58 はそれを明示的に書き出します。Bitcoin のアドレスが 1 で始まるのは、バージョンバイトが 0x00 だからです。
Base58 は Base58Check と同じですか?
違います。Base58Check は、ペイロードに 4 バイトのダブル SHA-256 チェックサムを付け足してから Base58 を適用したものです。Bitcoin のアドレスと WIF 秘密鍵はこちらを使い、Solana のアドレスと IPFS CIDv0 は素の Base58 を使います。チェックサム付きの形式には Base58Check ツールを使ってください。
Base58 は入力よりどれくらい長くなりますか?
ランダムなデータなら約 37%(log 256 / log 58 ≈ 1.366)で、Base64 の 33% より少し多めです。正確な長さは値によって決まり、ランダムな 32 バイトは 43〜44 文字になりますが、32 個のゼロバイトは 32 個の 1 になります。