Develop with pleasure!

福岡でCloudとかBlockchainとか。

オフチェーンプロトコルのプライバシーを向上させるオンチェーンウォレットのポリシーを定義したBIP-326

最近オフチェーンプロトコルのプライバシーを向上させるために、オンチェーンウォレットで実装が推奨されるポリシーが、BIP-326として定義された↓

https://github.com/bitcoin/bips/blob/master/bip-0326.mediawiki

Informational BIPなのでコンセンサスに影響するものではなく、各ウォレットへの対応が期待される。

プライバシーの向上というのは、現状のLightningチャネルなどのオフチェーン・コントラクトでは、nLockTimeやnSequenceなどのタイムロック機能を使ったトランザクションを構築しており、これらの値が設定されたトランザクションがオンチェーン上に現れると、それがオフチェーン・コントラクトであることを識別できる可能性がある。

これに対して、通常のオンチェーンウォレットでも支払いをする際に、これらのnLockTimeやnSequenceの値を設定することで、オフチェーン・コントラクトの識別をしにくくしようというもの。

また、現時点で脅威ではないけど、将来ブロック報酬の割合が少なくなり手数料収入がメインとなった場合に、マイナーにとって価値のある(手数料の高い)過去のトランザクションをマイニングするような攻撃が考えられる。今回のポリシーの適用による副次的な効果として、このようなフィー・スナイピング攻撃を防止することができる。

具体的には、オンチェーンウォレットで支払いをするトランザクションを作成する際に、現在の最新ブロックの次のブロック以降でマイニング可能になるようnLockTimeもしくはnSequenceの値を設定するという内容。どちらを使用するかは50%の確率で決める。

nLockTimeの場合は、単純に次のブロックのブロック高を設定すればいいけど、nSequenceの場合は、インプットで使用するUTXOの承認数+1をインプットのnSequenceの値にセットする。この辺りの具体的な仕組みは、以前GBEC動画でも解説してる↓

goblockchain.network

仕様の詳細については、BIP参照。以下はBIPの意訳。

概要

このドキュメントは、BIP341 Taprootを使用する、あるタイプのウォレットの動作を提案するものであり、Coin SwapやLightning、Discrete Log ContranctsなどのPoint Time Locked Contract(PTLC)を利用するオフチェーンプロトコルに、より大きな匿名セットを提供する。

動機

最近、BitcoinにTaprootが追加され、ウォレットソフトウェアがTaprootウォレットを実装しようとしいる。ここですぐに行動すれば、オフチェーンプロトコルのプライバシーを改善できるユニークな位置にいる。

Taprootは、Hash Time Locked Contract(HTLC)に代わるよりプライベートなものとしてPoint Time Locked Contract(PTLC)を可能にする。(例えばLightningチャネルなどの)オフチェーンコントラクトが、HTLCの代わりにPTLCを使って閉じられた場合、ブロックチェーンにはハッシュ値とプリイメージの代わりに通常のTaprootのスクリプトが現れるだけになる。しかし、コントラクトがタイムロックのパスを使って閉じられた場合、ブロックチェーン上のトランザクションでは、OP_CHECKSEQUENCEVERIFYnSequence値を参照するが、どちらも現在あまり一般的ではなく、クロージングトランザクションが特別で珍しいものとしてマークされることになる。

このBIPでは、Bitcoin Coreのようなオンチェーンウォレットも、BIP68のように、TaprootトランザクションでnSequenceフィールドをセットすることで、オフチェーンプロトコルのプライバシーとファンジビリティを改善することを提案している。これは、通常のnLocktimeのアンチ・フィー・スナイピング保護の代わりになる。その結果、ブロックチェーンの監視者が、nSequence値を持つTaprootの支払いを確認した場合、これは、ウォレットからの通常の支払いか、タイムロックが使われたオフチェーンの決済トランザクションのどちらかである。この2つのケースは区別がつかず、ビットコインのプライバシーとファンジビリティを大きく向上させることができる。コミュニティとウォレット開発者は、ウォレットへのTaproot自体の採用と同時に、nSequenceトランザクションの匿名セットが構築され始めるように、この実装を今すぐ行うべきだ。

背景

フィー・スナイピング

フィー・スナイピングは、低インフレの未来において、ビットコインのマイニングに悪いインセンティブが働くと仮定した場合の結果である。大規模なマイナーにとっては、ベストブロックとmempoolのトランザクションの価値は、ベストブロックをオーファンにするために意図的に2つのブロックをマイニングしようとするコストによって上回る可能性がある。しかし、nLocktimeやnSequenceを使ったアンチ・フィー・スナイピングの保護があれば、悪意あるマイナーは最初のブロックに格納可能なトランザクションを使い果たしてしまう。つまり2つめのブロックに格納する必要がでてくる。アンチ・フィー・スナイピングは、ブロックチェーンを前進させるインセンティブを高める。

nLocktimeフィールドは、現在このように使用されている。Bitcoin CoreとElectrumで実装されており、最近の全トランザクションの約20%で採用されている。

絶対的なロックタイムと相対的なロックタイム

nLocktimeは絶対的なロックタイムで、あるブロック高またはUNIX時間後にのみトランザクションがマイニングできるようにするものである。これが広く採用されることで、オフチェーンプロトコルに優れた匿名性がもたらされた可能性がある。残念ながらこれらのプロトコルでは、相対的なロックタイムも一般的に使用されている。これはクロージングトランザクションが承認された場合にのみカウントダウンクロックが動きだすため、(例えばLightingのペイメントチャネルやCoinSwapなどにょうに)コントラクトを無限に開いたままにすることができるからだ。

絶対的なロックタイムもまだ使用されているため、nLockTimeを使用し続ける必要があるが、nSequenceもよく使用される。

トランザクションのピン留め

トランザクションのピン留めは、帯域はCPU、メモリを消費する攻撃に対するノードの保護を悪用して、手数料の引き上げを法外に高くする手法だ。これは、マルチパーティコントラクトプロトコル(Lightning NetworkやCoinSwapなど)において、手数料管理を難しくする可能性がある。この問題を解決するいつの可能な方法は、すべての支払い条件に1ブロックの相対タイムロック(1 OP_CSV)を含め、未承認のUTXOの使用を不可能にすることだ。このような1ブロック分のタイムロックは、nSequenceの値を1にして作成することもできる。Bitcoinの多くのオンチェーントランザクションは、わずか1〜2ブロック前に作成されたインプットを使用している。このBIPに従えば、nSequence = 1のそのようなトランザクションは、トランザクションのピン留めを無効にするオフチェーントランザクショントラフィックをカバーする。

仕様

ウォレットがBIP341のTaprootで保護されたUTXOを使用するトランザクションを作成する場合、現在のブロックではなく先頭の次のブロックでのみマイニングされるようにすることで、フィー・スナイピングを阻止するためにnLockTimeの値またはnSequenceの値のいずれかを設定する必要がある。このBIPは、nLockTimeを使用する確率を50%、nSequenceを使用する確率を50%と提案している。nSequenceを設定する場合、トランザクションに複数のインプットがある場合は、そのうち少なくとも1つのインプットに適用する必要がある。オンチェーンウォレットはインプットをランダムに選択することを推奨する。

ウォレットはまた、nLockTimeおよびnSequenceの値をさらに後ろに設定する第2のランダム条件を持つべきで、そうすれば何らかの理由で遅延するトランザクション(例えば、高レイテンシーのミックスネットなど)は、より良いプライバシーを持つことができる。既存の動作は、10%の確率で0〜99の間の乱数を選択し、それを現在のブロック高から減算する。例として、参考文献にリンクされているBitcoin CoreやElectrumのソースコードを参照してほしい。

nSequenceは、ブロックの距離に対して65535までしかエンコードできないため、使用されるUTXOに65535以上の承認がある場合、ウォレットはnLockTimeを使用する必要がある。

擬似コード

def apply_anti_fee_sniping_fields(transaction, rbf_set):
    # bip68 requires v=2
    transaction.version = 2
    # Initialize all nsequence to indicate the requested RBF state
    # nsequence can not be 2**32 - 1 in order for nlocktime to take effect
    for input in transaction.inputs:
        if rbf_set:
            input.nsequence = 2**32 - 3
        else:
            input.nsequence = 2**32 - 2
    # always set nlocktime if any of the transaction inputs have more
    # confirmations than 65535 or are not taproot inputs, or have
    # unconfirmed inputs
    # otherwise choose either nlocktime or nsequence with 50% probability
    if not rbf_set || any(map(lambda input: input.confirmations() > 65535
            || !input.is_taproot() || input.confirmations() == 0,
            transaction.inputs)) || randint(2) == 0:
        transaction.nlocktime = blockchain.height()
        if randint(10) == 0:
            transaction.nlocktime = max(0, transaction.nlocktime
            - randint(0, 99))
        # nsequence must be set in order for nlocktime to take effect
    else:
        transaction.nlocktime = 0
        input_index = randint(len(transaction.inputs))
        transaction.inputs[input_index].nsequence = transaction.inputs\
            [input_index].confirmations()
        if randint(10) == 0:
            transaction.inputs[input_index].nsequence = max(1,
                transaction.inputs[input_index].nsequence - randint(0, 99))

互換性

このBIPは、コンセンサスの変更を必要としない。ウォレットが一方的に、そして徐々に採用することができる。しかし、より高いプライバシーのためには、ソフトウェアができるだけ早くそれを採用することが望ましいだろう。理想的には開発者がTaprootウォレットを実行する過程で、Taprootが使われた始めた時に、すでにnSequenceのコードが含まれているようにすること。

すべてのウォレットソフトウェアは、既にUTXOの承認回数を記録しているので、nSequneceフィールドを設定するのに必要な情報は既に得られている。