Bitcoinの支払いで一般的なのは送金相手の公開鍵に対して支払いを行うPay to PublicKey Hash=P2KH。これに対し、公開鍵の代わりにスクリプトを用いるのがPay to Script Hash=P2SH。
bips/bip-0016.mediawiki at master · bitcoin/bips · GitHub
BIP-16で定義されているPay to Script Hashについてざっと訳してみる。
BIP-16は、Bitcoinのスクリプトシステムの新しい標準トランザクションタイプ(P2SH)について記述したもので、この新しいタイプのトランザクションに適用される追加のバリデーションルールを定義したもの。
仕様
採掘されたブロックに含まれるこの新しいトランザクションタイプは以下のように定義される。
OP_HASH160 [20-byte-hash-value] OP_EQUAL
この[20-byte-hash-value]の部分は、opcode(0x14)に続いて20byteのデータをスタックにプッシュするものである。(この20byteの部分が、redeemScriptのハッシュ値になる)
この新しいトランザクションタイプはscriptSigによって復元される。
...signatures... {serialized script}
これらのpay-to-scriptを使った送金をしたBitcoinを利用する(出金)ためには、redeemScriptと呼ばれるシリアライズされたスクリプトが必要になる。
トランザクションを中継したり、新しいブロックに組み入れる際に、これらのoutpointsを検証するルールは以下のとおり。
- scriptSig内に"push data"以外のオペレーションがある場合はエラーとする。
- 署名と{serialized script}から初期スタックが作成された後、スクリプトのハッシュを計算し、outpoins内のハッシュと異なる場合はエラーとする。
- {serialized script}は初期スタックからPOPされ、スタックとscriptPubKeyとしてデシリアライズされたスクリプトを使って再度トランザクションの検証を行う。
このブロック内のトランザクションを検証する新しいルールは、2012/4/1より適用される。ブロックチェーン内の2012/4/1以前のトランザクションについては、この新しいルールでの検証は失敗する。そのため古いトランザクションは古いルールで検証する必要がある。
↓は、(マルチシグではなく)単一の署名を行うトランザクションのscriptPubKeyとscriptSigの例。
scriptSig: [signature] {[pubkey] OP_CHECKSIG} scriptPubKey: OP_HASH160 [20-byte-hash of {[pubkey] OP_CHECKSIG} ] OP_EQUAL
{serialized script}の署名演算は、↓のカウント方法に従って1ブロックあたり20,000演算まで許可されてる。
- 評価の有無に関らず、OP_CHECKSIG と OP_CHECKSIGVERIFY を1署名演算としてカウントされる。
- 評価の有無に関らず、OP_CHECKMULTISIG と OP_CHECKMULTISIGVERIFYは、OP_1からOP_16に先んじて1〜16の署名演算としてカウントされる。
- 他の全てのOP_CHECKMULTISIG と OP_CHECKMULTISIGVERIFYは20署名演算としてカウントされる。
例)
↓で3回の署名演算
{2 [pubkey1] [pubkey2] [pubkey3] 3 OP_CHECKMULTISIG}
↓で22回の署名演算
{OP_CHECKSIG OP_IF OP_CHECKSIGVERIFY OP_ELSE OP_CHECKMULTISIGVERIFY OP_ENDIF}
論拠
このBIPはBIP-12(opcode (OP_EVAL) の仕様)を置き換えるものである。
このBIP及びP2SHのアドレスを定義したBIP-13に関しては、不要であると考えている人もいて、複雑な多重署名のトランザクションタイプは単純に送信者の完全な{serialized script}によってサポートされるべきという意見もある。著者はこのBIPが、既に資金を送付するために作られているBase58エンコードされた20byteのBitcoinアドレスに対して、多重署名を組み込むための最小の仕様であると信じている。
特別な形式のscriptPubKey(今回のP2SH)を認識し、それが検出された際に余分な検証をするというのはかっこ悪いけど、他の代替方法もそれぞれ複雑で不格好だし、式言語を拡張していくのも危険な方法になる。
この署名演算のカウントルールは、{serialized script}を静的にスキャンすることで簡単かつ迅速に実装することを意図している。Bitcoinは採掘者によるDoS攻撃を防ぐために、ブロックあたりの最大署名演算数を制限している。もしこの制限が無いと、不正な採掘者が数十万の楕円曲線暗号の署名演算を必要とするブロックをブロードキャストする可能性があり、そうなると他のネットワークがその検証している間に次のブロックの計算を優先的に開始できるという攻撃が可能になる。
ここに古い実装で確認された1つの攻撃方法がある。(実際に行うのは困難だが)
- 攻撃者は古いソフトウェアを使ってP2SHのトランザクションを作成し(新しい実装では無効なトランザクション)、それを使って自分自身にいくつかコインを送信する。
- 続いて攻撃者は、支払いが行われたP2SHのトランザクションを使って今度は標準的なトランザクションを作成し、古いソフトウェアを使っている他者(被害者)にそのトランザクションで支払いを行う。
- 攻撃者は両方のトランザクション含むブロックを採掘する
被害者が1-confirmation(Bitcoinのconfirmation回数が1回)の支払いを受け入れる場合、他のネットワークで攻撃者の無効なブロックを上書きした際に、2つのトランザクションは無効となり攻撃者が勝利する。
ただこの攻撃は、他のネットワークで無効とされるブロックを生成する必要があるためコストが高い。ブロック作成のコストが高いし、高額な取引の場合1-confirmationが受け入れられるケースはほとんど無い。
後方互換姓
これらのトランザクションは古い実装では非標準なもので、こういったトランザクションやこういったトランザクション含むブロックを中継することはない。
古い実装では、このBIPをサポートするソフトウェアで作成されたブロックを検証する際、{serialize script}のハッシュ値が一致するかどうかの検証は行うが、それ以外の検証は行わない。
悪質なP2SHトランザクションによるブロックチェーンの分割を回避する際に1つ注意しておくケースがある。
- 新しいクライアントや採掘者にとっては無効なP2SHであっても、古いクライアントや採掘者にとっては有効である。
ソフトウェアをアップデートし、長期間ブロックチェーンの分割が発生しないことを確認するには、50%以上の採掘者が新しいトランザクションタイプのフル検証をサポートしなければならないのと同時に、古い検証ルールから新しいルールに切り替えなければならない。
マイニングの50%以上このBIPをサポートしているかどうかを判断するには、採掘者はソフトウェアをアップデートするよう求められ、採掘者が作成したブロック報酬のコインベースのトランザクションのインプットに"/P2SH/"という文字列をプットする。
2012/2/1にブロックチェーン上で過去7日間の間にP2SHをサポートしているブロックがいくつあるか調査する。もしハッシュ化の大部分がこの新しい検証ルールをサポートしていない場合、ロールアウトは延期される。(現状P2SHによるBitcoinの送付が可能なところをみると無事ロールアウトされた?)