10章_セグウィット
1. Segwitの実装背景
1.1. トランザクション展性問題
1.1.1. タイムロックについて
ビットコインには「タイムロック」という機能がある。タイムロックとは
「本来すぐにブロードキャストされてブロックに組み込まれるトランザクションを、遅らせて組み込まれるようにする」ためのもの。
たとえば...
Tx1: 2024年 12月22日にロックタイムが設定されたトランザクション
Tx2: Tx1と同じ出力を使ったトランザクション
Tx3: 2025年 12月28日にロックタイムが設定されたトランザクション。Tx2の出力を使う。
を使うと、以下のようなことができる。
1. 本日、Tx1でビットコインを送付したい相手に送る。
2. 2024年12月28日が来ると、相手はTx2をブロードキャストすることで受け取れる。受け取らせない場合は3へ
3. Tx2を作り、Tx3を相手に渡した上でTx2をブロードキャストする。これで、Tx2は無効化される。
ロックタイム単体で使うというより、スクリプトを組み合わせて、指定した時刻以降でしか使えないBTCを設定するために使われることが多い。
1.1.2. txidは簡単に書き換えられる?
先ほどと同じシーンを考える。
ある攻撃者はTx2を少し書き換えたTx2Mというトランザクションを作る。これは、
txidが異なっているのに、Tx2もTx2Mも両方有効である
という問題を持っている。つまり万が一Tx2Mが承認されてブロックに格納された場合、Tx2を指すTx3は無効化されてしまう。
署名を有効なままにtxidを書き換えるには3つの方法がある
署名の形式を他の有効な形式に変更する
暗号学的なテクニックを駆使して署名を書き換える
「何もしない命令」を追加する
これらはリレーポリシーによって制限されるが、マイナーが全てそれに従う保証はない。つまり、原理的にこれを阻止する方法が必要になる。
1.2. 署名の非効率性
5.2.1.3で示されたように、トランザクションに署名をする前に署名スクリプトを全て取り除くので、あるトランザクションに対する署名はどれも同じハッシュになってしまう
→つまり、出力を変えても同じアドレスに支払いをする場合ハッシュは同じになるので署名は変更されない。
これを避けるために、署名スクリプトに対して出力の公開鍵スクリプトをコピーしてくる。この手順が非常に手間で、入力が増えるとそれに応じて処理時間も増えてしまう。これをO(n)にしたい。
1.3. 帯域幅を無駄使いする
これは簡易ウォレットを実装する際に問題となる。署名スクリプトはトランザクションの中で5割近くを占めるため、帯域幅の節約のためには受け入れたくない。しかしtxidの計算には署名スクリプトが含まれているので、このままでは省略はできない。
1.4. Script言語のアップデート問題
Script言語に新しい演算子を追加するとき、それらはすべて旧バージョンでは「何もしない」を意味するOP_NOP上に実装されている。しかし、これは10種類しか用意されていないし、後方互換性のためにはOP_NOPと同じ動作になる必要がある
2. 問題まとめ
タイムロック時のtxid書き換え問題
署名の非効率性
簡易ウォレットが不要な署名スクリプトをダウンロードする必要がある
Script言語のアップデートが困難
3. Segwit fixes this
Segwitは一言で言えば、
署名スクリプトをブロックの外に出す
しかし、単純にそれを行うと従来の方法でtxidを計算するソフトウェアの後方互換性は確保されない。そこで
署名スクリプトの内容を空にする
署名(witness)は添付データとして外部に保持される
というアップデートを行う。
3.1. アドレスの変更
Segwitでは、アドレスも変更される。これまではbase58checkを使っていたが、Bech32というNostrでも使われている方式に変更される。
bc1qeqzjk7vume5wmrdgz5xyehh54cchdjag6jdmkj
bc: 可読部
1: 区切り
それ以降: バージョンとwitnessプログラムが符号化されている。
Nostrでお馴染みの方式。ただし、改良版のbech32mというものもある。メリットは
全て小文字なのでQRコードが小さくなり、アドレスが読みやすい
チェックサムが4文字までの誤りを100%検出できる
3.2. witnessプログラムとは?
witnessプログラムには、2つの種類がある。
P2WPKH: P2PKHに対応するもので、単純にあるアドレスを指す。20バイト。
P2WSH: P2WSHに対応するもので、Scriptをハッシュ化したもの。32バイト。
プログラムという名前がついているが、P2WPKHは単にアドレスを指すものなのでプログラムっぽくはない。P2WSHはScriptの情報が入っているので、プログラムっぽいが。
※バージョン情報が入っていることがプログラムっぽいらしい
P2WSHについての詳細はここでは書かない。P2SHとやっていることはほぼ同じ。
3.3. 後方互換性
古いノードは、一言でいえばこのような新しいタイプの署名を一切検証しない。つまりこのノードに限って言えば、だれでも出力を引き出せてしまう。この本の執筆時点ではネットワークの95%がSegwitに対応しているので、ほかのノードでブロックされて無効化される。
また、古いウォレットから新しいウォレットに送金するために、P2SHにみせかけたP2WSH、P2PKHに見せかけた[P2WPKHを作成する仕様もある。
これで、古いウォレットとノードの両方に後方互換性が用意されている。
3.4. ブロックへのトランザクションの組み込み
ブロックについても変更点が生まれる。コインベーストランザクションにwitness commitment = witness root hash + witness reserved valueを結合したハッシュが含まれている必要がある。
witness root hash: ブロック内のすべてのトランザクションwtxid(witnessを含んだトランザクション全体)のマークルルート
witness reserved value: どんな値でもよい?ただしノードは知っている必要がある
3.5. 署名のハッシュ方法変更
署名の検証時間を短縮するため、トランザクション全体を「クリーン」な状態でハッシュした中間ハッシュに対して以下のように足し合わせ、それぞれを署名する。
入力のtxidとインデックス+スクリプト+支払額+中間ハッシュ
使われる出力ごとに署名が作成され、witnessに格納される。全体をハッシュするのは「中間ハッシュ」を作るときの一回のみ。支払額が署名の対象になっているのは、簡易ウォレットが受取額を検証できるようにするため。
3.6. 結局、このアップデートで何が改善されたのか?
タイムロック時のtxid書き換え問題: 署名データを分離することで、txidは署名スクリプトの変更に対して不変となる。
署名の非効率性: 署名のハッシュ方法が変更され、署名ごとにトランザクション全体をハッシングする必要がなくなる。
簡易ウォレットが不要な署名スクリプトをダウンロードする必要がある: 署名スクリプトが分離されたので、帯域幅が削減される。
Script言語のアップデートが困難: バージョン情報が埋め込まれたため、「特定のバージョンまで対応したノード」のような運用が可能になる。
さらに、ブロックに署名スクリプトが含まれなくなったので、ブロックのデータ量も節約できている。(ブロックサイズの計算方法も変化している)
4. おまけ
https://coin.z.com/jp/corp/information/bch/
Segwitが導入された当時、単にブロックサイズを大きくすることで対応するべきだと主張する派閥もあった。結果的にSegwitが採用されたが、それに反対した派閥はビットコインをハードフォークしビットコインキャッシュ(BCH)をリリースした。ハードフォークの詳細については11章で解説される(はず)。