ふくふくHukuhuku Inc.
EP.09Algorithms 9分公開: 2026-05-11

Merkle Tree:Bitcoin・Git・IPFS が使う改ざん検出のハッシュツリー

「巨大データのどこか 1 bit が変わったら、ハッシュ 1 つで検出できる」Merkle Tree を Python で実装。Bitcoin の SPV、Git のオブジェクト、IPFS の中身。

#Merkle Tree#ハッシュ#Bitcoin#Git
CO📔 Google Colab で開く(上から順にセルを実行)
シェア

Bitcoin の 1 ブロックには数千のトランザクションが入っているが、ブロックヘッダは 80 バイトGit のリポジトリの 100 万コミットの整合性が、現在の HEAD ハッシュ 1 つで検証できる。これらすべての中核に Merkle Tree (ハッシュツリー) がある。

1. これで何が動いているか

  • Bitcoin / Ethereum: ブロック内トランザクションの整合性検証
  • Git: commit / tree / blob の階層 (実は Merkle DAG)
  • IPFS: 分散ファイルストレージのコンテンツアドレッシング
  • DynamoDB / Cassandra: 分散レプリカ間の差分同期
  • ZFS / BTRFS: ファイルシステムの整合性検証
  • Certificate Transparency: SSL 証明書の改ざん検出 (Google Chrome)

2. 仕組みのざっくり

  • : 元データの SHA-256 ハッシュ
  • 内部ノード: 左右の子ハッシュを連結 (concat) したもののハッシュ
  • 根 (root): ツリーの最上位、これ 1 つで全データを代表
  • 葉が奇数個: 一般的に最後の葉を複製 (Bitcoin 方式)
  • 改ざん検出: 1 bit でも変わると、その葉から root まで全ノードのハッシュが変わる

3. Python 実装 (動作確認済)

純粋 Python の Merkle Tree
Python
import hashlib
def sha256(s):    return hashlib.sha256(s.encode() if isinstance(s, str) else s).hexdigest()
def merkle_root(leaves):    '''葉のリストから Merkle root を計算'''    if not leaves:        return None    h = [sha256(l) for l in leaves]    while len(h) > 1:        if len(h) % 2:            h.append(h[-1])  # 奇数個なら末尾を複製        h = [sha256(h[i] + h[i+1]) for i in range(0, len(h), 2)]    return h[0]
# 4 トランザクションのブロックtxs = ['Alice→Bob: 1 BTC', 'Carol→Dave: 0.5 BTC',       'Eve→Frank: 2 BTC', 'Grace→Henry: 0.1 BTC']root = merkle_root(txs)print(f'Merkle root: {root}')
# 1 文字でも変えると root が変わるtxs_tampered = ['Alice→Bob: 1 BTC', 'Carol→Dave: 0.5 BTC',                'Eve→Frank: 2 BTC', 'Grace→Henry: 0.2 BTC']  # 0.1 → 0.2root_t = merkle_root(txs_tampered)print(f'改ざん後 root: {root_t}')print(f'検出: {root != root_t}')
# 実機実行結果:# Merkle root: <ハッシュ># 改ざん後 root: <別のハッシュ># 検出: True

4. Merkle Proof の実装

葉が root に含まれることを log₂ N 個のハッシュで証明
Python
def build_tree(leaves):    '''全レベルのハッシュを保持'''    levels = [[sha256(l) for l in leaves]]    while len(levels[-1]) > 1:        cur = levels[-1]        if len(cur) % 2: cur = cur + [cur[-1]]        levels.append([sha256(cur[i]+cur[i+1]) for i in range(0, len(cur), 2)])    return levels
def merkle_proof(levels, index):    '''葉 index に対する Merkle proof を生成'''    proof = []    for level in levels[:-1]:        sibling = index ^ 1  # 兄弟は最下位 bit 反転        if sibling >= len(level): sibling = index        proof.append((sibling > index, level[sibling]))  # (right?, hash)        index //= 2    return proof
def verify_proof(leaf, proof, root):    '''proof を使って root に到達するか検証'''    h = sha256(leaf)    for is_right, sibling in proof:        h = sha256(h + sibling) if is_right else sha256(sibling + h)    return h == root
txs = [f'tx{i}' for i in range(8)]levels = build_tree(txs)root = levels[-1][0]
# tx3 の proof を作って検証proof = merkle_proof(levels, 3)print(f'proof 長: {len(proof)} (= log₂ 8 = 3)')print(f'検証: {verify_proof("tx3", proof, root)}')print(f'偽装検証: {verify_proof("tx3_fake", proof, root)}')

5. メリットとデメリット

観点Merkle Tree全データハッシュ
改ざん検出✓ (root 1 つで全体)
部分証明O(log n) のハッシュで可能全データ必要
差分同期差分木の比較で高速全件比較
追加コスト葉数 × 2 のハッシュ計算1 ハッシュ

6. 関連ツール

  • hashlib (Python 標準): SHA-256 / SHA-3
  • py-merkle-tools: Merkle Tree 実装
  • ethereum/trie (Python): Ethereum の Merkle Patricia Trie
  • bitcoin-cli: Bitcoin の Merkle proof コマンド

7. 次の話

EP.10 では PageRank を扱います。Google を作った 1998 年のアルゴリズム を Python で実装。Web グラフの「重要なページ」を行列計算で求める数学的な美しさ。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp