トランザクションが検証される流れ|詳解ビットコイン⑨
『詳解ビットコイン』(Kalle Rosenbaum著、オライリージャパン)を読んでいます。その個人的なまとめとして書いていきます。
検証その1 プログラムを実行する
トランザクションの検証を以下の2つに分け、まずは「プログラムを実行する」について記載します。
プログラムを実行する
UTXOセットでの検証を行う
ひとつ前の記事に記載したように、ビットコインのトランザクションには、Scriptという言語で書かれたプログラムが含まれています。
検証時に実行されるプログラムは2つの要素で構成されていて、その要素とは、署名スクリプト(sig-script)と公開鍵スクリプト(pub-script)です。
署名スクリプトは、支払いを行うためのトランザクションの入力部分に含まれています。一方、検証に使われる公開鍵スクリプトは、支払いに使うUTXOを生み出したトランザクションの出力部分に含まれます。公開鍵スクリプトは、支払いを行うためのトランザクションに含まれてはいないものの、TXIDやidxからたどれるという感じなのかと思います。
プログラムの上部には署名スクリプト、下部には公開鍵スクリプトを配置して、そのプログラムを上から下に実行していきます。
その際、「スタック」というものを使います。スタックとは、データを入れたり出したりできるもので、例えば、下記の例であれば、まず署名部分をスタックに積むことになります。
署名を積んだら、次は公開鍵を署名の上に積むことになります。
この次は、「OP_DUP」という要素です。これは演算子といって、スタックにある要素を使い、特定の計算をすることを指示しています。たとえば、「OP_DUP」は、スタックトップの要素を複製して積むことを命じています。
検証者はこのようにして、プログラムを上から下に実行していきます。そして「true」という結果が出たら、検証結果が合格ということになります。
ちなみに、上記のプログラムを実行していくと、デジタル署名の検証なども完了できるようになっています。
検証その2 UTXOセットでの検証
トランザクションの検証のためには、プログラムの実行以外の作業も行われています。その作業の目的は以下の2つです。
使用済みのお金(コイン)を使っていないか
存在しないお金(コイン)を使っていないか
使用済みのお金を使うというのは、すでに支払いのために差し出したコインを、再度支払いに使うということです。これは現実世界では基本的にできません。しかし、デジタルの世界では十分あり得ます。そのため、予防策が必要というわけです。
存在しないお金での支払いとは、受け取っていないコインでの支払い(残高以上を支払うこと)や、偽造したコインでの支払いを指します。これも予防すべきです。
UTXOセットとは
上記を防ぐために行われるのは、「UTXOセット」と呼ばれるデータを使った検証作業です。UTXOセットとは、UTXOの一覧表です。
検証者は自分専用のUTXOセットを持っていて、検証時に使います。
より具体的には、検証時には、トランザクションの入力に入っているものがUTXOセット内にあるかをチェックします。UTXO内になかったら、二重支払いや偽造の可能性が高いということで、不合格とできます。
トランザクションの入力がUTXO内にあれば、検証を続けることができます。そして、プログラムの実行結果が「true」になったときに、そのトランザクションの入力をUTXOセットから取り除きます。
P2PKHのトランザクション
P2PKHは、もっとも一般的なトランザクションタイプです。そのスクリプトプログラムはこの記事の冒頭に記載したものと同じで、以下のようになっています。
そして、以下のようにスタックを使って検証を進めます。
以降では、プログラム内の要素の意味を大まかに記載します。
署名:
秘密鍵を使って作った署名です。単なるデータなので、検証者はスタックトップに積み重ねるという処理をします。作業後は以下のようになります。
鍵:
デジタル署名の検証に使う公開鍵です。単なるデータなので、検証者はスタックトップに積み重ねるという処理をします。作業後は以下のようになります。
OP_DUP:
演算子です。指示している内容は、「スタックトップを取り除くことなく複製し、複製したものスタックに積み重ねよ」ということです。作業後は以下のようになります。
OP_HASH160:
演算子です。指示している内容は、「スタックトップを取り除いて、それをSHA-256でハッシュして、さらにRIPEMED160でハッシングせよ。そして、そのハッシュをスタックに積み重ねよ」ということです。作業後は以下のようになります。
PKH:
このトランザクションに署名した人のPKHです。単なるデータなので、検証者はスタックトップに積み重ねるという処理をします。作業後は以下のようになります。
OP_EQUALVERIFY:
演算子です。指示している内容は、「スタックトップの2つを取り出し、それらが一致するかを確認せよ。」ということです。一致した場合、作業後は以下のような様子になります。
OP_CHECKSIG:
演算子です。指示している内容は、「スタックトップの公開鍵と署名を取り出して検証せよ。成功したならtureをスタックトップに配置せよ。」ということです。検証に成功した場合、作業後は以下のような様子になります。
OP_EQUALVERIFYについて
OP_EQUALVERIFYの部分では、次の図のようにして2つのPKHを比較し、一致するかを確かめました。
なぜこの作業をするのかを考えてみたいと思います。
そもそも1つ目のPKHは、公開鍵スクリプトに含まれていたものであり、UTXOの持ち主のPKHです。
2つ目のPKHは、トランザクション作成者の公開鍵を「OP_HASH160」の指示に従って、署名スクリプトに含まれる公開鍵をハッシングして作ったものです。これは、トランザクション作成者の公開鍵から作られています。
上記より、比較しているPKHのうちの1つは、お金の持ち主のもので、もう一つはトランザクション作成者のものです。この点を踏まえて、次の状況を考えてみてください。
UTXOの持ち主がアリスで、トランザクションの作成者がジョンだったとします。ジョンは、アリスがまだ使っていないお金(UTXO)を自分のもののように使おうとしているのです。この場合、検証が成功してはいけません。
しかし、「2つのPKHの一致を確認する」という作業をしないと、検証が成功してしまいます。次の演算子「OP_CHECKSIG」で確認するのは、署名スクリプトに含まれている署名と公開鍵を使っての検証です。そのため、ジョンが自分の秘密鍵でつくった署名と、ジョンの公開鍵での検証になり、トランザクションが途中で改ざんされなければ成功します。
そもそも、署名スクリプトに含まれている公開鍵が、UTXOセットの持ち主(アリス)の公開鍵であることを確かめる必要がありますよね。その作業こそが、「2つのPKHの一致を確認する」という作業です。
P2SHのトランザクション
ビットコインでは、P2PKHでの支払いのほかにも、様々なタイプの支払いが行われています。P2PKHの支払いは万能ではなく、たとえば、マルチシグでの署名をしたい人などのニーズはかなえられません。
そこで、上記のようなニーズをかなえられるトランザクションとして登場したのが、P2SHです。
そもそもSHとは
SH(スクリプトハッシュ)は、ちょっとややこしいのですが、以下のような感じで、プログラムを圧縮するとできる 「Redeem Script」を、ハッシングした結果にできるものです。
プログラム部分をそのまま公開鍵スクリプトに含めればよいのですが、そうなると不都合が生じます。
例えば、公開鍵スクリプトに特別なプログラムを仕込むには、マルチシグのアドレスに送金してくれる人に、プログラムを含めてもらうようにお願いすることになりますが、そうなると送金者がたくさんの手数料を払わなければいけません。
また、送金者のウォレットアプリが、受信者が指定するプログラムを公開鍵スクリプトに含められる仕様かどうかわかりません。しかも、受信者が指定するプログラムは、複数通り発生するので、いちいちそれに合わせるのは非効率です。
そこで、プログラムを圧縮し、「SH」という単一の形をとったのだと考えられます。
P2SHのトランザクションの検証
P2SHのトランザクションを検証する上では、以下のようにしてプログラムを実行してくことになります。
途中に、Redeem Scriptを回答することで、その人がニーズを満たすために行いたいプログラムが実行されます。
coinbaseトランザクション
本書では補足として、coinbaseトランザクションの説明もされています。coinbaseトランザクションとは、ブロック生成報酬を受け取るためにマイナーが作るトランザクションです。
coinbaseトランザクションの入力部分はcoinbaseと呼ばれていて、通常のトランザクションとは違った形になっています。
TXIDには、「0」が羅列された文字列が入ります。idxには「-1」が入ります。sig-scriptは、任意の文字でOKです。