システム全体像
polkaは複数の技術を組み合わせて、分散型の検証可能なWebを実現しています。このページでは、システムの構成要素と、それらがどのように連携するかを説明します。
システム構成
polkaは、以下のレイヤーから構成されています。
データ層: ATProtocol Repo データの構造化と検証を担当します。Merkle Search Treeにより、すべてのデータをまとめて検証できます。
ストレージ層: Git + 静的ファイルホスティング データの永続化と配信を担当します。Gitでバージョン管理し、静的ファイルとしてHTTPSで配信します。
アイデンティティ層: did:web + HTTPS/DNS ドメインと公開鍵の紐付けを担当します。既存のHTTPS/DNSインフラを信頼の基盤とします。
発見層: Nostr + Bloom Filter ユーザーの発見を担当します。Nostrリレーに自分の存在を広告し、興味のあるタグを持つユーザーを見つけます。
検証層: 電子署名 (Secp256k1) データの真正性を担当します。すべてのデータは署名され、検証されます。
これらのレイヤーが協調して動作することで、polkaの分散型Webが実現されます。
データ層: ATProtocol Repo
polkaのデータは、ATProtocolのリポジトリ形式で管理されます。
Merkle Search Tree
Merkle Search Tree(MST)は、複数のデータをソート済みの木構造で管理し、ルートハッシュで全体を検証できる仕組みです。
polkaでは、タグの階層構造、投稿、プロフィールなど、すべてのデータがMSTに格納されます。MSTのルートハッシュに署名することで、データ全体の整合性が保証されます。
BlockStore
実際のデータは、CIDをキーとしたブロックストアに保存されます。各ブロックはCBOR形式でエンコードされ、そのハッシュがCIDとなります。
クライアントは必要なブロックだけを取得できるため、リポジトリ全体をダウンロードする必要はありません。
Commitオブジェクト
Commitオブジェクトは、MSTのルート、DID、署名を含みます。このCommitがリポジトリ全体のスナップショットとなり、検証の起点となります。
ストレージ層: Git + 静的ファイルホスティング
polkaのデータ配信は、極めてシンプルです。静的ファイルをHTTPSで配信するだけです。
ローカルでのデータ管理
ユーザーのローカルで、データはCAR形式のファイルとして保存されます。このファイルには、すべてのブロックが含まれています。
ビルドプロセス
データを公開するとき、CARファイルから個別のブロックファイルが生成されます。各ブロックは {CID} という名前のファイルとして保存され、ルートCIDは ROOT というファイルに書き込まれます。
Gitによるバージョン管理
生成されたブロックファイルは、Gitリポジトリにコミットされます。これにより、データの変更履歴が記録され、必要に応じて過去の状態に戻すことができます。
静的ホスティング
Gitリポジトリは、GitHub Pages、Netlify、Caddy、Nginxなど、任意の静的ファイルホスティングサービスで公開されます。CORSヘッダーさえ適切に設定されていれば、どのホスティングでも動作します。
クライアントは、https://example.com/polka/ROOT でルートCIDを取得し、https://example.com/polka/{cid} で各ブロックを取得します。
アイデンティティ層: did:web
polkaは、ドメイン名と公開鍵の紐付けに did:web を使用します。
DID Document
ユーザーは、自分のドメインの .well-known/did.json に DID Document を配置します。このドキュメントには、公開鍵とpolkaリポジトリのサービスエンドポイントが記載されています。
複数鍵の対応
DID Documentには複数の公開鍵を登録できます。これにより、鍵のローテーションや、複数デバイスでの運用が可能になります。
クライアントは、いずれかの鍵で署名が検証できれば、そのデータを正当なものとして受け入れます。
発見層: Nostr
polkaは、ユーザー発見にNostrを使用します。
Kind 25565: タグ広告
ユーザーは、自分が使っているタグを Bloom Filter にエンコードし、Nostr リレーに広告します。イベントの kind は 25565 で、content に DID と Bloom Filter が含まれます。
Bloom Filterによるマッチング
Bloom Filterは確率的データ構造です。クライアントは受信したBloom Filterに対して、興味のあるタグが含まれているかをチェックします。
偽陽性の可能性はありますが、偽陰性はありません。マッチした場合、クライアントは相手のDIDを解決し、実際のデータを取得して確認します。
Bloom Filterの偽陽性は、自分と関係のないトピックのユーザーも発見できる、スパイスとして位置付けています。
発見後のフォロー
一度マッチしたユーザーを見つけたら、そのユーザーのタグノードをローカルに保存します。以降は、Nostrリレーを経由せず、HTTPS経由で直接データを取得します。
Nostrは「ブートストラップ」の役割であり、継続的なデータ取得には使用されません。
検証層: 電子署名
polkaのすべてのデータは、Secp256k1電子署名により保護されています。
署名の流れ
- ユーザーがデータを作成・更新する
- MSTが再構築され、新しいルートハッシュが生成される
- Commitオブジェクトが作成され、秘密鍵で署名される
- 署名されたCommitとブロックが保存される
検証の流れ
- クライアントがROOTからルートCIDを取得
- ルートCIDでCommitブロックを取得
- did:webからユーザーの公開鍵を取得
- Commitの署名を検証
- 署名が正しければ、MSTを走査してデータを取得
改ざんされたデータは署名検証で失敗し、CIDが一致しないブロックは拒否されます。
なぜATProtocolとNostrなのか
ATProtocol: 検証可能なデータベースとして
polkaでは、ユーザーごとにタグの階層構造を持ちます。たとえば、japan/kokeshi や anime/ikizulive/polka のような階層です。これらのタグは相互にリンクし合い、グラフ構造を形成します。
このグラフ全体を検証可能にする必要がありました。1つのタグだけでなく、グラフ全体の整合性を効率よく証明する仕組みが必要だったのです。
ATProtocolのデータ構造、特にMerkle Search Treeは、まさにこの用途に最適でした。MSTは複数のデータをまとめてハッシュ化し、そのルートハッシュに署名することで、グラフ全体の正しさを効率的に証明できます。
polkaはATProtocolを、Blueskyのような大規模SNSではなく、単純な「検証可能なデータベース」として使っています。
Nostr: ブートストラップとして
分散型システムには、「他のユーザーをどうやって見つけるか」という根本的な課題があります。
polkaはこの問題に対して、Nostrの既存インフラを活用しています。ユーザーはNostrリレーに自分の存在を広告し、興味のあるタグを持つ他のユーザーを発見します。
重要なのは、Nostrは一時的な発見の手段でしかない、という点です。一度つながりを見つければ、その後のデータ取得はHTTPS経由で直接行われます。リレーがダウンしても、既存のフォロー関係は影響を受けません。
この設計により、大規模なリレーインフラに依存せず、最小限の調整だけでネットワークが機能します。