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とします。
code:sign
L1 L1nonce L2 L2nonce L3 L3nonce
\ / \ / \ /
v v v v v v
L1A=H("LnBranch",L1||L1nonce) L2A=H("LnBranch",L2nonce||L2) L3A=H("LnBranch",L3nonce||L3)
仮にL1A < L2Aとします:
L1A L2A L3A=H("LnBranch",L3nonce||L3)
\ / |
v v v
L1A2A=H("LnBranch",L1A||L2A) L3A=H("LnBranch",L3nonce||L3)
仮にL1A2A > L3Aとします:
L1A2A=H("LnBranch",L1A||L2A) L3A
\ /
v v
Root=H("LnBranch",L3A||L1A2A)
署名は次のようになります:
Signature = SIG("lightninginvoicesignature", Root, nodekey)
オファー
オファーはinvoice_requestの前段階であり、読者はオファーに基づいてインボイス(または複数のインボイス)を要求します。オファーは特定のインボイスよりも長期間有効である可能性があるため、いくつか異なる特徴を持っています。特に、金額はライトニングの通貨以外でも指定できます。また、QRコード内に収まりやすいようにコンパクトに設計されています。
オファーの非署名TLV要素はinvoice_requestおよびinvoiceメッセージにも反映されるため、それぞれ固有で異なるTLV範囲を持ちます。
オファーの人間が読めるプレフィックスはlnoです。
オファーのTLVフィールド
code:offer
1. tlv_stream: offer
2. types:
1. type: 2 (offer_chains)
2. data:
* [...*chain_hash:chains]
1. type: 4 (offer_metadata)
2. data:
* [...*byte:data]
1. type: 6 (offer_currency)
2. data:
* [...*utf8:iso4217]
1. type: 8 (offer_amount)
2. data:
* [tu64:amount]
1. type: 10 (offer_description)
2. data:
* [...*utf8:description]
1. type: 12 (offer_features)
2. data:
* [...*byte:features]
1. type: 14 (offer_absolute_expiry)
2. data:
* [tu64:seconds_from_epoch]
1. type: 16 (offer_paths)
2. data:
* [...*blinded_path:paths]
1. type: 18 (offer_issuer)
2. data:
* [...*utf8:issuer]
1. type: 20 (offer_quantity_max)
2. data:
* [tu64:max]
1. type: 22 (offer_issuer_id)
2. data:
* [point:id]
オファーの要件
オファーの作成者の要件
オファーを作成する者は、以下の要件を満たす必要があります:
TLVフィールドは、1から79および1,000,000,000から1,999,999,999の範囲内に設定しなければなりません(MUST NOT)。
インボイスのチェーンがビットコインのみでない場合:
オファーが有効なチェーンをoffer_chainsで指定しなければなりません(MUST)。
そうでない場合
offer_chainsを省略すべきです(SHOULD)。ビットコインのみのチェーンを示唆します。
成功する支払いのために特定の最小offer_amountが必要な場合:
期待される金額(アイテムごと)をoffer_amountで設定しなければなりません(MUST)。
offer_amountの通貨がチェーン内のすべてのエントリと一致する場合:
最小のライトニングで支払い可能な単位(例えばビットコインのミリサトシ)でoffer_amountを指定しなければなりません(MUST)。
それ以外の場合、offer_currencyをISO 4217の3文字コードで指定しなければなりません(MUST)。
offer_amountはISO 4217エクスポーネントで調整された通貨単位(例:USDセント)で指定しなければなりません(MUST)。
支払いの目的を完全に説明するoffer_descriptionを設定しなければなりません(MUST)。
上記に該当しない場合:
offer_amountを設定してはなりません(MUST NOT)。
offer_currencyを設定してはなりません(MUST NOT)。
offer_descriptionを設定してもよいです(MAY)。
自分の使用のためにoffer_metadataを設定してもよいです(MAY)。
bolt12オファーの機能をサポートする場合:
offer_features.featuresにbolt12の機能ビットマップを設定しなければなりません(MUST)。
オファーの有効期限がある場合:
offer_absolute_expiryに、1970年1月1日午前0時(UTC)からの秒数を設定しなければなりません(MUST)。その時間を過ぎたinvoice_requestは試行されるべきではありません。
プライベートチャネルのみで接続されている場合:
公開可能なノードからノードまでの1つ以上のパスを含むoffer_pathsを含めなければなりません(MUST)。
そうでない場合
offer_pathsを含めてもよいです(MAY)。
offer_pathsが含まれている場合:
offer_issuer_idを設定してもよいです(MAY)。
そうでない場合
インボイスを要求するノードの公開鍵にoffer_issuer_idを設定しなければなりません(MUST)。
offer_issuerを設定する場合:
インボイスの発行者を明確に識別するように設定すべきです(SHOULD)。
ドメイン名を含む場合:
user@domainまたはdomainで始めるべきです(SHOULD)。
スペースと追加のテキストが続くことも許可されます(MAY)。
単一のインボイスで複数のアイテムを提供できる場合:
最大数量がわかっている場合:
offer_quantity_maxにその最大値を設定しなければなりません(MUST)。
offer_quantity_maxを0に設定してはなりません(MUST NOT)。
そうでない場合
offer_quantity_maxを0に設定しなければなりません(MUST)。
その他の場合
offer_quantity_maxを設定してはなりません(MUST NOT)。
オファーの読み取り者の要件
オファーを読み取る者は、以下の要件を満たす必要があります:
オファーにTLVフィールドが1から79および1,000,000,000から1,999,999,999の範囲外のものが含まれている場合:
オファーに応答してはなりません(MUST NOT)。
offer_featuresに未知の奇数ビットが含まれており、それがゼロでない場合:
そのビットを無視しなければなりません(MUST)。
offer_featuresに未知の偶数ビットが含まれており、それがゼロでない場合:
オファーに応答してはなりません(MUST NOT)。
不明なビットをユーザーに示すべきです(SHOULD)。
offer_chainsが設定されていない場合:
ノードがビットコインのインボイスを受け付けない場合:
オファーに応答してはなりません(MUST NOT)。
そうでない場合(offer_chainsが設定されている場合):
ノードがチェーンのいずれのインボイスも受け付けない場合:
オファーに応答してはなりません(MUST NOT)。
offer_amountが設定されていてoffer_descriptionが設定されていない場合:
オファーに応答してはなりません(MUST NOT)。
offer_currencyが設定されていてoffer_amountが設定されていない場合:
オファーに応答してはなりません(MUST NOT)。
offer_issuer_idおよびoffer_pathsのいずれも設定されていない場合:
オファーに応答してはなりません(MUST NOT)。
offer_paths内のblinded_pathのnum_hopsが0である場合:
オファーに応答してはなりません(MUST NOT)。
offer_amountを使用してユーザーにコスト見積もりを提供する場合:
offer_currencyフィールドが設定されている場合
その通貨単位を考慮しなければなりません(MUST)。
それ以外の場合、最小のライトニングで支払い可能な単位(例えばビットコインのミリサトシ)を考慮しなければなりません(MUST)。
受け取ったinvoice_amountがその見積もりと大きく異なる場合
ユーザーに警告しなければなりません(MUST)。
現在の時刻がoffer_absolute_expiryを超えている場合:
オファーに応答してはなりません(MUST NOT)。
インボイス要求を送信することを選択した場合、オニオンメッセージを送信します:
offer_pathsが設定されている場合:
オファーメッセージをそのパス内の最終onion_msg_hop.blinded_node_idに送信しなければなりません(MUST)。
そうでない場合:
offer_issuer_idにオニオンメッセージを送信しなければなりません(MUST)。
同時に複数のインボイス要求オニオンメッセージを送信してもよいです(MAY)。
根拠
オファー全体はinvoice_requestに反映されます。これは完全性を保つため(すべての情報がインボイスに返されるようにするため)であり、オファーノードがステートレスであることを可能にします。これにより、offer_metadataは特に有用になります。なぜなら、他のフィールドを検証するための認証クッキーを含めることができるからです。
オファーフィールドはinvoice_request(およびその後のインボイス)にコピーされるため、異なる範囲が必要です。範囲1-79は通常の範囲であり、さらに10億の自己割り当て実験範囲があります。
署名は不要であり、より長い文字列になるため(低性能なカメラでのQRコード使用が制限される可能性があります)、オファーにエラーがある場合、要求にすべての非署名フィールドが含まれているためインボイスは発行されません。
offer_pathsが設定されている場合、offer_issuer_idは簡潔さのため省略できます。各パス内の最終blinded_node_idが宛先の有効な公開鍵として機能するからです。
offer_amountが異なる通貨である可能性があるため(offer_currencyフィールドを使用)、それは単なるガイドにすぎません。発行者はインボイスを生成する際にinvoice_amountのミリサトシ数に変換します。または、インボイス要求でinvreq_amountに正確な金額を指定することもできますが、発行者が合意しない場合は拒否される可能性があります。
offer_quantity_maxは1に設定することが許可されています。一見無意味に見えますが、在庫に基づいたシステムでは有用です。「残り1つのみ」のオファー生成を特別扱いするのは困難だからです。
オファーは、対価を期待せずに単にお金を送るために使用することができます(チップ、称賛、寄付など)。この場合、offer_descriptionフィールドは任意です(この場合、offer_issuerフィールドが非常に有用です!)。具体的なものに対して料金を請求する場合、説明はユーザーが支払った内容を知るために重要です。
インボイス要求
インボイス要求はインボイスを要求するものであり、インボイス要求の人間が読めるプレフィックスはlnrです。
インボイス要求には、ワークフローの観点からはほぼ同じですが、ユーザーの視点からは大きく異なる2つの用途があります。
1つ目はオファーへの応答です。これはoffer_issuer_idまたはoffer_pathsとその他のオファーの詳細を含み、通常オニオンメッセージで受け取ります。もしそれが有効で、既知のオファーを指している場合、通常はオニオンメッセージのreply_pathフィールドを使用してインボイスで応答します。
2つ目は、オファーなしでインボイス要求を公開する場合です(例えばQRコードを介して)。この場合、offer_issuer_idもoffer_pathsも含まれず、代わりにinvreq_payer_id(場合によってはinvreq_pathsも)を設定します。他のオファーフィールドはインボイス要求の作成者によって埋められ、一種の「お金を送るオファー」のような形になります。
注:invreq_metadataは他のinvreqフィールドの80-159の範囲には含まれず、数値的に「最初のTLVエントリ」となります。これにより、マークルリーフが推測不可能になり、将来的なコンパクトな表現がフィールドを隠しつつ署名の検証を可能にします。
invoice_request のTLVフィールド
code:invoice_request
1. tlv_stream: invoice_request
2. types:
1. type: 0 (invreq_metadata)
2. data:
* [...*byte:blob]
1. type: 2 (offer_chains)
2. data:
* [...*chain_hash:chains]
1. type: 4 (offer_metadata)
2. data:
* [...*byte:data]
1. type: 6 (offer_currency)
2. data:
* [...*utf8:iso4217]
1. type: 8 (offer_amount)
2. data:
* [tu64:amount]
1. type: 10 (offer_description)
2. data:
* [...*utf8:description]
1. type: 12 (offer_features)
2. data:
* [...*byte:features]
1. type: 14 (offer_absolute_expiry)
2. data:
* [tu64:seconds_from_epoch]
1. type: 16 (offer_paths)
2. data:
* [...*blinded_path:paths]
1. type: 18 (offer_issuer)
2. data:
* [...*utf8:issuer]
1. type: 20 (offer_quantity_max)
2. data:
* [tu64:max]
1. type: 22 (offer_issuer_id)
2. data:
* [point:id]
1. type: 80 (invreq_chain)
2. data:
* [chain_hash:chain]
1. type: 82 (invreq_amount)
2. data:
* [tu64:msat]
1. type: 84 (invreq_features)
2. data:
* [...*byte:features]
1. type: 86 (invreq_quantity)
2. data:
* [tu64:quantity]
1. type: 88 (invreq_payer_id)
2. data:
* [point:key]
1. type: 89 (invreq_payer_note)
2. data:
* [...*utf8:note]
1. type: 90 (invreq_paths)
2. data:
* [...*blinded_path:paths]
1. type: 240 (signature)
2. data:
* [bip340sig:sig]
インボイス要求の要件
作成者の要件
インボイス要求を作成する者は、以下の要件を満たす必要があります:
オファーに応答している場合:
オファーからすべてのフィールドをコピーしなければなりません(未知のフィールドを含む)(MUST)。
offer_chainsが設定されている場合:
invreq_chainをoffer_chainsのいずれかに設定しなければなりません(MUST)。ただし、そのチェーンがビットコインの場合、invreq_chainを省略すべきです(SHOULD)。
それ以外の場合:
invreq_chainを設定する場合、ビットコインに設定しなければなりません(MUST)。
invreq_payer_idを使用して署名を行い、signature.sigを設定しなければなりません(MUST)。
offer_amountが存在しない場合:
invreq_amountを指定しなければなりません(MUST)。
それ以外の場合:
invreq_amountを省略してもよいです(MAY)。
invreq_amountを設定する場合:
invreq_amount.msatをoffer_amount(および、もし存在する場合はoffer_currencyおよびinvreq_quantity)で期待される金額以上に設定しなければなりません(MUST)。
invreq_payer_idを一時的な公開鍵に設定しなければなりません(MUST)。
invreq_payer_idに対応する秘密鍵を記憶しておかなければなりません(MUST)。
offer_quantity_maxが存在する場合:
invreq_quantityを0より大きい値に設定しなければなりません(MUST)。
offer_quantity_maxがゼロでない場合:
invreq_quantityをoffer_quantity_max以下に設定しなければなりません(MUST)。
それ以外の場合:
invreq_quantityを設定してはなりません(MUST NOT)。
オファーに応答していない場合:
offer_descriptionを支払いの目的を完全に説明するものに設定しなければなりません(MUST)。
offer_absolute_expiryおよびoffer_issuerをオファーのように設定するか、設定しないかしなければなりません(MUST)。
invreq_payer_idを設定しなければなりません(これはオファーに対するoffer_issuer_idと同様に設定されます)(MUST)。
invreq_pathsを設定するか、オファーに対するoffer_pathsと同様に設定しなければなりません(MUST)。
以下を含めてはなりません(MUST NOT):署名、offer_metadata、offer_chains、offer_amount、offer_currency、offer_features、offer_quantity_max、offer_paths、offer_issuer_id。
インボイスのチェーンがビットコインのみでない場合:
オファーが有効なチェーンをinvreq_chainで指定しなければなりません(MUST)。
invreq_amountを設定しなければなりません(MUST)。
署名以外のTLVフィールドを0〜159および1,000,000,000〜2,999,999,999の範囲外に設定してはなりません(MUST NOT)。
invreq_metadataを予測不可能なバイト列に設定しなければなりません(MUST)。
invreq_amountを設定する場合:
invreq_chain(またはinvreq_chainがない場合はビットコイン)の最小ライトニング支払い単位(例えばビットコインのミリサトシ)の倍数でmsatを設定しなければなりません(MUST)。
bolt12インボイス要求機能をサポートしている場合:
invreq_features.featuresに機能のビットマップを設定しなければなりません(MUST)。
読み取り者の要件
インボイス要求を読み取る者は、以下の要件を満たす必要があります:
invreq_payer_idまたはinvreq_metadataが存在しない場合、インボイス要求を拒否しなければなりません(MUST)。
署名以外のTLVフィールドが0〜159および1,000,000,000〜2,999,999,999の範囲外にある場合、インボイス要求を拒否しなければなりません(MUST)。
invreq_featuresに未知の奇数ビットが含まれており、それがゼロでない場合
そのビットを無視しなければなりません(MUST)。
invreq_featuresに未知の偶数ビットが含まれており、それがゼロでない場合
インボイス要求を拒否しなければなりません(MUST)。
invreq_payer_idを使用した署名が正しくない場合
インボイス要求を拒否しなければなりません(MUST)。
invreq_paths内のblinded_pathのnum_hopsが0である場合
インボイス要求を拒否しなければなりません(MUST)。
offer_issuer_idが存在し、invreq_metadataが以前のインボイス要求と同一である場合
以前のインボイスで単に応答してもよいです(MAY)。
そうでない場合
以前のインボイスで応答してはなりません(MUST NOT)。
offer_issuer_idまたはoffer_pathsが存在する場合(オファーへの応答):
オファーフィールドが有効で期限切れでないオファーと正確に一致しない場合
インボイス要求を拒否しなければなりません(MUST)。
offer_pathsが存在する場合
そのパスのいずれかから到着していないインボイス要求を無視しなければなりません(MUST)。
そうでない場合
blinded_pathを経由して到着したインボイス要求を無視しなければなりません(MUST)。
offer_quantity_maxが存在する場合:
invreq_quantityフィールドがない場合、インボイス要求を拒否しなければなりません(MUST)。
offer_quantity_maxがゼロでない場合:
invreq_quantityがゼロであるか、offer_quantity_maxを超えている場合、インボイス要求を拒否しなければなりません(MUST)。
そうでない場合
invreq_quantityフィールドがある場合、インボイス要求を拒否しなければなりません(MUST)。
offer_amountが存在する場合:
offer_amountを使用して期待される金額を計算しなければなりません(MUST)。
offer_currencyがinvreq_chainの通貨でない場合、invreq_chainの通貨に変換します。
invreq_quantityが存在する場合、invreq_quantity.quantityで乗算します。
invreq_amountが存在する場合:
invreq_amount.msatが期待される金額より少ない場合、インボイス要求を拒否しなければなりません(MUST)。
invreq_amount.msatが期待される金額を大幅に超える場合、インボイス要求を拒否してもよいです(MAY)。
(offer_amountがない場合):
invreq_amountが含まれていない場合、インボイス要求を拒否しなければなりません(MUST)。
オニオンメッセージreply_pathを使用してインボイスを送信すべきです(SHOULD)。
(offer_issuer_idまたはoffer_pathsがなく、オファーへの応答でない場合):
以下のいずれかが存在する場合、インボイス要求を拒否しなければなりません(MUST):
offer_chains、offer_features、offer_quantity_max。
invreq_amountが存在しない場合、インボイス要求を拒否しなければなりません(MUST)。
offer_amount(またはoffer_currency)をユーザーへの情報表示に使用してもよいです(MAY)。
インボイスを応答として送信する場合:
invreq_pathsが存在する場合、それを使用して送信しなければなりません(MUST)。そうでない場合、invreq_payer_idをノードIDとして使用して送信しなければなりません(MUST)。
invreq_chainが存在しない場合:
ビットコインがサポートされていないチェーンである場合、インボイス要求を拒否しなければなりません(MUST)。
それ以外の場合:
invreq_chain.chainがサポートされていないチェーンである場合、インボイス要求を拒否しなければなりません(MUST)。
根拠
invreq_metadataには通常、invreq_payer_idの導出に関する情報が含まれます。これは情報が漏洩しないようにする必要があります(例えば、単純なBIP-32導出パスを使用するなど)。有効なシステムとしては、ノードが基本の支払い者キーを保持し、ここに128ビットの調整値をエンコードする方法があります。payer_idは、基本キーをSHA256(payer_base_pubkey || tweak)で調整することで導出されます。これは(存在する場合)最初のエントリでもあり、ハッシュ化のための予測不可能なノンスを保証します。
invreq_payer_noteを使用すると、褒めたり、挑発したり、あるいはインボイスにグラフィティを刻んで他の人に見せることができます。
ユーザーは、インボイス要求でinvreq_amountを指定することでチップを送ったり、送った金額を隠したりすることができます。オファーがoffer_amountを指定している場合でも、インボイス要求の金額が期待される金額を超えている場合にのみ受け取ります(つまり、offer_amountを通貨変換後、必要に応じてinvreq_quantityで乗算した額を超える場合)。
オファーに応答しないインボイス要求では、現在、チェーンの通貨でinvreq_amountを明示的に指定する必要があります。そのため、offer_amountおよびoffer_currencyは冗長ですが、支払人に送信者がどのようにinvreq_amountを導出したかを知らせる情報として役立つ場合があります。
offer_pathsが存在する場合にそれを使用する要件により、ノードが直接尋ねられた際にオファーの発信元であることを明かさないようにします。同様に、オファーに対して正しいパスが使用される要件により、同じノードが別のオファーを作成したことを明かさないようにします。