用語集 / 開発者向けリファレンス
OP_CHECKSIG
- OP_CHECKSIGとは?
- OP_CHECKSIGはスタックから公開鍵と署名を取り出し、その署名がこのトランザクションにコミットしていることを検証します。これは、実際にビットコインの所有を証明するチェックです。
これまでに使われたビットコインのほぼすべてが、この1つのオペコード、バイト0xacを通っています。署名の末尾に付いたsighashバイトに従ってトランザクションのダイジェストを構築し、署名を公開鍵と照合して、trueまたはfalseをプッシュします。falseをプッシュした場合、その支出は成立しません。コード上でビットコインを所有するとは、まさにこのことに尽きます。
仕組み
OP_CHECKSIGは2つの項目を取り出します。公開鍵が先、その下にある署名が次です。そして、通常は1つにまとめられがちな3つの別々の処理を行います。
1つ目は、何に署名したのかを決めることです。署名の最後のバイトは署名の一部ではありません。ダイジェストがトランザクションのどの部分を対象にしたかを示すフラグです。圧倒的に多い値は0x01で、すべてのインプットとすべてのアウトプットを意味するため、署名後にトランザクションのどの部分を変えても無効になります。このダイジェストを構築する手順は2回置き換えられています。SegWitバージョン0の支出向けのBIP-143と、Taproot向けのBIP-341で、いずれもトランザクションのサイズの2乗でハッシュ計算のコストが増えるのを防ぐためでした。
2つ目は、エンコーディングをチェックすることであり、ビットコインはここで異例に厳格です。レガシー署名は有効なDERでなければならず、フラグバイトを含めて最大72バイトで、S値は曲線位数の下半分に収まっている必要があります。厳格なエンコーディング規則は2015年7月のBIP-66として導入されました。切り替えの際、いくつかの大手プールが検証していないブロックヘッダーを基にブロックを構築していたため、ある日の午後に6つのブロックが孤立しました。マイニングと検証が別の作業であることを示す最も明快な例として、今も残っています。
3つ目は、検証することです。レガシーとSegWitバージョン0の支出はsecp256k1上のECDSAを使います。Tapscriptは代わりにBIP-340の64バイトのSchnorr署名を使い、検証に失敗した場合は何か他のものではなく空の項目をプッシュすることを要求し、検証した署名1つにつきスクリプトの予算から50のweight unitを消費します。
どこで見られるか
OP_CHECKSIGは、存在するほぼすべてのスクリプトを締めくくります。レガシーのアウトプットはこれで終わり、ネイティブの単一鍵SegWit支出は、それらのバイトがチェーン上に現れなくても同じ最終オペコードを持つ同じテンプレートを実行し、ライトニングネットワークのコミットメントスクリプトはタイムロックと取り消しの分岐の後にこれで終わります。
ブロックエクスプローラーを見るときは、例外を知っておく価値があります。Taprootのキーパス支出はスクリプトをまったく実行しません。ノードはアウトプット内の32バイトの鍵に対して直接1つの署名を検証します。表示するアセンブリも指し示すオペコードも存在しません。まさにそのため、この支出タイプは最も安価で最もプライバシーに優れたものになり、所有者だけが支出するbc1pアドレスがチェーン上で他のどのアドレスとも同じに見えるのです。
OP_CHECKSIG vs OP_CHECKSIGADD
OP_CHECKSIGADDが存在するのは、OP_CHECKSIGが数えられないからです。複数当事者のスクリプトでは、提示された署名のうちいくつが正しかったかを知る必要があり、旧設計では鍵と署名のリスト全体を一度に飲み込む単一のオペコードでそれに答えていました。Tapscriptはこれを、署名を1つ検証してスタック上の累計に1を加えるオペコードに置き換えたため、2-of-3のポリシーは2との比較で終わる短いシーケンスになります。この変更は体裁の問題ではありません。署名を1つずつ数えることがSchnorr署名のバッチ検証を可能にし、Taprootの検証速度はこのバッチ検証から来ています。