先日、Delving Bitcoinで開示された、btcdで発見された相対的タイムロックのコンセンサスバグについて↓
相対的タイムロック
トランザクションの相対的なタイムロック機能は以下の2つのBIPで定義されている。
- BIP-68:トランザクションインプットの
nSequence
の値を相対的なタイムロック時間として扱う仕様の追加
シーケンス番号を使ったRelative lock-timeについて(BIP-68) - Develop with pleasure! - BIP-112:BIP-68のタイムロックの値をスクリプトで制御するためのOP_CSV opcodeの導入
relative lock-timeをスクリプトで検証するOP_CSV(BIP-112) - Develop with pleasure!
これらの仕様はソフトフォークとして2016年6月にBitcoinに導入された。
今では、ライトニングネットワークなどさまざまなコントラクトプロトコルの構成要素の1つとして利用されている。
BIPにも記載されているように、この機能をトランザクションで有効にするためには、トランザクションのバージョンを2以上に設定する必要がある(ソフトフォーク前に事前署名したトランザクションが無効にならないようにするための措置)。
バグの内容
問題はトランザクションのバージョンの型。元々Bitcoinの実装では、このバージョンは符号付き整数で管理されている。バージョンを負の値として解釈することができる。
ただ、BIP-68の参照実装のセクションのコード内には、
tx.nVersion is signed integer so requires cast to unsigned otherwise we would be doing a signed comparison and half the range of nVersion wouldn't support BIP 68.
と、符号付き整数(int32)から符号なし整数(uint32)へのキャストするよう記載されている。符号付き整数のまま比較すると、バージョンのとり得る値の半分がBIP 68をサポートできなくなるため。
Bitcoin Coreではこのキャストを行っているが、btcdではこのキャストが行われていなかったというのがバグの内容。
バグの影響
btcdでは上記のキャストが行われないため、符号付き整数として解釈した場合に、負の値のバージョンを持つトランザクションを構築することが可能になる。
そのようなトランザクションがあると、
- Bitcoin Coreでは相対的タイムロックのルールを強制する。
- btcdから見ると負の値で2未満なので相対的タイムロックの適用対象外とみなされる。
たとえば、OP_CSVロックされているUTXOを使用するトランザクションを構成し、事前署名していても、OP_CSVの評価時にTxのバージョンが2未満であると解釈され無効なトランザクションとして判定される。
ただ、負の値にするためには最上位bitが1になる必要があるので、符号なし整数としては、2147483648以上の値をバージョンとして指定する必要があるけど、
- そういったバージョンを設定したトランザクションを作成する一般的なウォレットは無いだろうし、
- Bitcoin Coreのリレーポリシーで現在許可されているバージョンは最小値が1、最大値が2なので、負の値のバージョンを持つトランザクションは拒否される(マイナーの協力でもない限りそういったトランザクションをブロックに含めるのもハードル高い)。
ただ、実際に発生するとチェーン分岐が発生する可能性があり、
- btcdを使用しているライトニングノードは、正しいチェーンの更新を受信できず、資金を失うリスク
- 悪意あるマイナーが(実質競合がいない)btcdチェーンでマイニングを続け、ユーザーに無効な支払いを受け入れさせる可能性
- マイナー自体がbtcdを使用している場合、無効なチェーンのマイニングを継続してリソースを無駄に消費する
といった影響が考えられるので、btcd使っている場合はv0.24.0へのアップグレードは必須。
バグの修正
修正はシンプルで、上記のキャストをするようにするというもの。修正のPR自体は、gofmtを適用するPRで、その中にuint32へのキャスト処理を入れ込んだみたい。
また、btcd以外にbitcoin-sでも修正が行われている↓
https://github.com/bitcoin-s/bitcoin-s/pull/5346
今回影響なかった、Bitcoin Coreにも符号付き整数として解釈した場合に負の値になるバージョン(0xffffffff
)のテストデータが新しく追加されてる↓
https://github.com/bitcoin/bitcoin/pull/29291
タイムライン
開示までのタイムラインは↓
- 2023-05-22 Lightning Labsへの最初の開示
- 2023-06-21 修正PRがbtcdにマージ
- 2023-12-31 btcd v0.24.0リリース
- 2024-01-22 開示
修正からリリースまでは結構あいてる。標準のリリースサイクルに含めたということなのかな?