レッスン 2

Base64 エンコードの仕組み

ビット、6 ビットグループ、64 文字のアルファベット。

Base64 がエレガントなのは、ビット2 の累乗ルックアップテーブル(アルファベット)という既知の概念を再利用しているからです。辞書的な文章変換や圧縮ステップはありません — 決定論的なビットの並べ替えと文字置換だけです。

バイトからビットストリームへ

1 バイトは 8 ビットです。3 バイトで 24 ビット:

Byte1: ########
Byte2: ########
Byte3: ########   → 順に 24 ビットを連結

Base64 は 24 ビットを 4 つの 6 ビット組(セクステット)に再グループ化します。

[######][######][######][######]
  ^        ^        ^        ^
 idx 0    idx 1    idx 2    idx 3

各 6 ビット値は 0–63 の範囲で、64 記号の 1 つをインデックスします。このインデックス数が文字通り 「base 64」 の由来です: 数字 0–63 の代わりに印字可能な ASCII 文字で base 64 の数を書いています。

標準アルファベット(RFC 形式)

従来の Base64 は次のように割り当てます。

0–25 → A–Z
26–51 → a–z
52–61 → 0–9
62 → '+'
63 → '/'

デコードは逆マップ: 記号 → 6 ビット → 元の 8 ビットグループを再構成。

手計算のミニ例(2 バイト → パディングの直感付き 4 文字)

日常で手計算する必要は稀ですが、直感を固めます。ASCII "Hi" を取ると:

  • H = 0x4801001000
  • i = 0x6901101001

16 ビットを連結: 0100100001101001

6 で割り切れる長さになるまでにゼロをパディング(パディングのレッスンで詳述):

010010 | 000110 | 100100 |
  18  |    6   |   36   |

4 番目のセクステットはさらに入力が来るまで不完全。シリアライザーは = プレースホルダーを出力します(次のレッスンで詳述)。ライブラリは機械的に処理 — 分割を見ると長さがなぜ伸びるか、破損が下流ビットをなぜ大きく狂わせるかが説明できます。

出力が約 33% 伸びる理由

3 バイト(24 ビット)の組ごとに、同じエントロピーを印字可能テキストに広げた 4 文字になります。単純化した平均: 入力 n バイトに対し、パディング前に約 ceil(4n/3) 文字。

n mod 3 != 0 のときは = パディングも加わります。このオーバーヘッドは想定内。Base64 はサイズと互換性のトレードオフです。

デコードの対称性

デコード:

  1. 各アルファベット文字 → 6 ビット値(+// の癖は後で選んだ variant 次第)。
  2. ビットを連結。
  3. 8 ビットチャンクに再グループ化。

文字列長が不正、または不正な記号(空白、間違ったアルファベットインデックス)があるとデコード失敗 — または緩いパーサーによって一貫性なく動作する、より悪い場合も。

要点

Base64 はビットを 6 ビットグループに再チャンクし、各チャンクを 64 個の決められた印字可能文字の 1 つに置き換えます。再グループ化をイメージできれば、パディングと URL-safe 置換は謎ではなくなります。

実践したいときは関連する DevCove ツールを使えます。任意であり、このレッスンの必須部分ではありません。

関連ツールを開く

コース概要へ戻る