BOLT12
BOLT12は、2020年にRusty Russell氏(Blockstreamのエンジニア)によって最初に提案されました。
BOLT12は、Lightning Networkの新しいプロトコル仕様であり、従来のBOLT11インボイスの制約を克服し、より柔軟でプライバシー保護された支払い要求(オファー)を可能にします。
BOLT12オファーの主な特徴:
再利用可能な支払い要求
BOLT11インボイスは一度限りの使用が推奨されていましたが、BOLT12オファーは再利用可能な支払いコードを提供します。これにより、同じオファーを複数回使用して支払いを受け取ることが可能となります。
受取人のプライバシー強化
BOLT12は、受取人のノードIDやIPアドレスを秘匿するために、ブラインドパス(blinded paths)と呼ばれる技術を使用します。これにより、受取人のプライバシーが向上します。
オンネットワークでのインボイス要求
オファーをスキャンした送信者は、Lightningネットワーク上でインボイス要求を送信し、受取人からユニークなインボイスを受け取ります。これにより、追加のサーバーを必要とせずに支払いプロセスが完結します。
BOLT12オファーの利点:
プライバシーの向上: 受取人の情報が秘匿されるため、プライバシーが強化されます。
柔軟性の向上: 再利用可能なオファーにより、支払い要求の管理が簡素化されます。
追加のインフラ不要: オンネットワークでのインボイス交換により、追加のサーバーやサービスを必要としません。
----------------------------------------------------------------------------------------------------------------------------
LND版の実装
LNDKは、Lightning Network Daemon(LND)とLightning Development Kit(LDK)を連携させ、BOLT 12の機能をLNDに外部から実装するためのスタンドアロンのデーモンです。
主な機能
オニオンメッセージの転送: LNDKは、LNDノードがオニオンメッセージを処理・転送できるようにします。これにより、プライバシー保護されたメッセージングが可能となります。
BOLT 12オファーの支払い: LNDKを使用することで、BOLT 12オファーを介した支払いが可能となり、より柔軟でプライバシーに配慮した支払い要求が実現します。
利用方法
LNDの設定: LNDKを使用するには、LND v0.18.0以降を、peersrpc、signrpc、walletrpcの各サブサーバーを有効にしてコンパイルし、--protocol.custom-message=513、--protocol.custom-nodeann=39、--protocol.custom-init=39のオプションを指定して起動する必要があります。
LNDKの設定: LNDKは、LNDのgRPCアドレスと認証情報を指定して起動します。これらの情報は、コマンドライン引数や設定ファイルで指定できます。
LNDKは、LNDとLDKの機能を組み合わせることで、BOLT 12の実装を外部から提供し、Lightning Networkの機能拡張をサポートします。
Lightning Development Kit(LDK)
Lightning Development Kit(LDK)は、Rustで書かれたモジュール化されたライブラリで、Lightning Networkの開発を支援するためのキットです。LDKは、特にウォレットやサービスプロバイダが、独自のカスタムなLightning Networkノードを構築したり、既存のアプリケーションにLightning Network機能を統合したりすることを容易にします。
----------------------------------------------------------------------------------------------------------------------------
BOLT12を翻訳
BOLT 11の制限
BOLT 11のインボイス形式は人気がありますが、いくつかの制限があります:
bech32エンコーディングが絡み合っており、他の形式(例えばライトニングネットワーク内での送信)では扱いにくいです。
インボイス全体に署名が適用されるため、インボイスの一部を公開せずに証明することが不可能です。
一般的にフィールドを外部で利用するために抽出することができません。hフィールドはdフィールドのブティック的な抽出でした。
「奇数でも問題ない」ルールの欠如により、後方互換性が難しくなっています。
金額を分ける「人間が読める」考えは問題を引き起こしました:pがしばしば誤って扱われ、pico-bitcoinでの金額は現代のsatoshiベースの計算よりも扱いにくいです。
開発者はbech32エンコーディングが拡張に問題があることを発見したため、置き換えるか破棄する必要があります。
経路内の他のノードによるプロービングを防ぐために設計されたpayment_secretは、インボイスが支払者と受取人の間でプライベートなままである場合にのみ有効でした。
インボイスはユーザーごとに与えられなければならず、同じユーザーに対して2回支払いが試みられると危険です。
支払いフローのシナリオ
ここでは、「ユーザー」は個々のユーザーのライトニングノードの略であり、「マーチャント」は何かを販売している、または販売したノードの略として使用します。
BOLT 12では、以下の2つの基本的な支払いフローがサポートされています:
一般的なユーザーがマーチャントに支払うフロー:
マーチャントがオファーを公開します(例えば、ウェブページやQRコードで)。
各ユーザーは、ライトニングネットワーク上でinvoice_requestメッセージを使用してユニークなインボイスを要求します。このメッセージにはオファーのフィールドが含まれます。
マーチャントはインボイスで応答します。
ユーザーはインボイスに従ってマーチャントに支払いを行います。
マーチャントがユーザーに支払うフロー(例えばATMや返金):
マーチャントが送金する金額を含むinvoice_requestを公開します。
ユーザーは、invoice_requestに記載された金額のインボイスをライトニングネットワーク上で(場合によっては一時的な)invoice_node_idを使用して送信します。
マーチャントはinvoice_node_idを確認し、正しい相手に支払おうとしていることを確認し、そのインボイスに対して支払いを行います。
支払いの証明と支払者の証明
通常のライトニングの「支払いの証明」は、インボイスが支払われたことを証明することしかできません(payment_hashのプレイメージを示すことで)。誰が支払ったかを証明することはできません。マーチャントはインボイスが支払われたと主張することができ、一度公開されると誰でもそのインボイスを支払ったと主張することが可能です。
invoice_requestでキーを提供することにより、支払者は自分がインボイスを要求したことを証明できます。さらに、BOLT 12のインボイス署名のマークル構造により、ユーザーは紛争が発生した場合にインボイスのフィールドを選択的に公開することが可能です。
エンコーディング
ここで記載されている各形式はTLV形式で表現されています。
サポートされているASCIIエンコーディングは、人間が読めるプレフィックスの後に 1、その後にbech32スタイルのデータ文字列が続きます。このデータ文字列はTLVを順に並べたもので、必要に応じて +(追加データが続くことを示す)を挿入することができます。bech32mとは異なり、チェックサムはありません。
要件
bolt12文字列の作成者:
すべて小文字かすべて大文字を使用しなければなりません(MUST)。
QRコードの場合、大文字を使用すべきです(SHOULD)。
その他の場合、小文字を使用すべきです(SHOULD)。
大きなbolt12文字列を分割するために、+を任意で使用し、その後に空白を追加することができます(MAY)。
bolt12文字列の読み取り者:
すべて小文字またはすべて大文字の文字列を処理しなければなりません(MUST)。
2つのbech32文字の間に + があり、その後にゼロまたは複数の空白文字がある場合:
+ と空白を削除しなければなりません(MUST)。
根拠
bech32の使用は任意ですが、ビットコインの世界では既に存在しています。現在、6文字の末尾のチェックサムは省略しています:QRコードには独自のチェックサムがあり、エラーが発生しても資金の損失にはならず、単に無効なオファー(または解析不能なオファー)となるだけです。
無視される + の使用は、Twitterのような限られたテキストフィールドでの使用を可能にします:
code:fields
lno1xxxxxxxx+
yyyyyyyyyyyy+
zzzzz
フォーマットはformat-string-test.jsonを参照してください。
署名の計算
すべての署名はBIP-340に従って作成され、そこで推奨されるタグ付けが行われます。そのため、H(tag,msg)はSHA256(SHA256(tag) || SHA256(tag) || msg)として定義され、SIG(tag,msg,key)はキーを使用してH(tag,msg)の署名を行います。
各形式は1つ以上の署名TLV要素(TLVタイプ240から1000までの範囲)を使用して署名されます。これらのタグは「lightning」|| メッセージ名 || フィールド名となり、msgはマークルルートです。「lightning」はリテラルな9バイトのASCII文字列で、メッセージ名は署名されるTLVストリームの名前(例:「invoice_request」または「invoice」)、フィールド名は署名を含むTLVフィールド(例:「signature」)です。
マークルツリーの構成はBIP-341で提案されているものと類似しており、各TLVリーフは証明において隣接ノードを公開しないようにするためにノンスリーフとペアになっています。
マークルツリーのリーフは、各TLVに対してTLV昇順で次のようになります:
H("LnLeaf",tlv)。
H("LnNonce"||first-tlv,tlv-type)。ここでfirst-tlvはストリーム内の数値的に最初のTLVエントリであり、tlv-typeは現在のTLVの「タイプ」フィールド(1〜9バイト)です。
マークルツリーの内部ノードはH("LnBranch", lesser-SHA256||greater-SHA256)です。この順序付けにより、証明がよりコンパクトになり、左右が自然に決定されます。
リーフの数が2のべき乗でない場合、ツリーの深さは不均等になり、最も深いツリーが最小オーダーのリーフに位置します。
例えば、TLV0、TLV1、TLV2(それぞれタイプ0、1、2)のTLVを持つインボイス署名のエンコーディングを考えます:
L1=H("LnLeaf",TLV0)
L1nonce=H("LnNonce"||TLV0,0)
L2=H("LnLeaf",TLV1)
L2nonce=H("LnNonce"||TLV0,1)
L3=H("LnLeaf",TLV2)
L3nonce=H("LnNonce"||TLV0,2)
仮にL1 < L1nonce、L2 > L2nonce、L3 > L3nonceとします。