マークル証明
API が返すすべての解決結果には、マークル証明が添えられています。これにより、結果を送ってきたサーバーを 信頼する代わりに、答えを状態ルートと突き合わせて確認できます。
ツリー
PiNS はすべての名前を 128 ビットの鍵空間上のコンパクト疎マークルツリーに保持します。名前の鍵は
SHA-256(domain_name) の先頭 16 バイトなので、名前は均等に分布し、自分の名前がどこに落ちるかを選べる人は
いません。
「コンパクト」とは、葉が固定の深さ 128 ではなく、鍵の接頭辞が一意になる最も浅い深さに置かれるという意味 です。数千の名前を保持するツリーでは、ほとんどの証明はせいぜい十数個のハッシュにすぎません — スマート フォンでも、ブラウザ拡張でも、ウォレットの中でも検証できるほど小さいのです。
検証器を書く前に知っておくべき 2 つの帰結:
- 証明の長さは可変です。 レスポンスから
proof_depthを読んでください。固定サイズを決して前提に しないでください。 - 空の部分木はどの高さでも 32 個のゼロバイトです。 そのため空のツリーのルートはすべてゼロです —
初期化直後のインデクサーが
0000…0000を報告するのは正常であって、壊れているわけではありません。
証明に含まれるもの
| フィールド | 意味 |
|---|---|
merkle_proof | 兄弟ハッシュ。[0] が最も深い(葉に最も近い) |
proof_depth | 兄弟ノードの数 — merkle_proof.length と等しくなければならない |
proof_terminal | 経路の末端にあるもの:Occupied、Vacant、Blocked のいずれか |
smt_root | これらの兄弟ノードが再構成するルート |
存在と不在
証明が「この名前は登録されていない」を「されている」と同じくらい説得力をもって言えるのは、まさに ターミナルのおかげです:
Occupied— 経路の末端にその鍵自身の葉があります。名前は存在し、渡されたレコードはツリーの中に あるまさにそれです。Vacant— そこには空の部分木があります。名前は登録されていません。Blocked— その位置を別の名前の葉が占めています。名前は登録されておらず、レスポンスにはブロックして いるレコードが添えられているので、それがそこで見つかった葉にハッシュされること、そしてその鍵が実際に 同じ接頭辞を共有していることを検証できます。
Blocked がなければ、インデクサーは「その場所は空だ」と主張して登録を隠せてしまうでしょう。ブロックして
いるレコードが丸ごと含まれているからこそ、その主張を受け入れる代わりに検証できるのです。
検証
レコードをハッシュして葉にし、各ステップで鍵のビットに従って左か右かを決めながら、兄弟ノードをルートへ
向けて畳み込みます。smt_root にたどり着けば、そのレコードはツリーがコミットしているものそのものです。
まだ 1 つ疑問が残ります。smt_root は本物のルートでしょうか? BNB Smart Chain 上のアンカーコントラクトに
尋ねれば答えが出ます。Python、PHP、JavaScript のテスト済みコードとともに、両方の手順が
証明の検証にあります。