ビットコインにおいてトランザクションが正しく実行されるためには、トランザクションスクリプトというプログラムを通すことが必要です。このスクリプトにより正しい送り手にトランザクションを送り、有効な受け手と判断された場合のみにトランザクションインプットが行えることになります。

このトランザクションスクリプトは一部かなりややこしい部分があるので、ここではできるだけ仕組みの部分をできるだけ丁寧に解説していきます。また、現在する5種類のトランザクションスクリプトについてもそれぞれ見ていきたいと思います。

 

トランザクションスクリプトとは

トランザクションスクリプトとは、ビットコインのトランザクションに不正がないか検証するためのプログラムです。つまり、トランザクションスクリプトによりトランザクションが本当に正しい送信者からのインプットであるのか、あるいは正しい送信先にアウトプットできているかチェックすることができるのです。

ビットコインのトランザクションはインプットとアウトプットから成っておりUTXOの消費と生成により実行されていきます。

参考:ビットコインのトランザクションにおける「UTXO」を分かりやすく解説してみた

このUTXOにトランザクションスクリプトがあり有効な条件下でのみトランザクションが実行されるようになっているのです。トランザクションスクリプトはScript言語により記述されています。そこで、まずはScript言語の概要を見ていきましょう。

 

Script言語の特徴

ビットコインのトランザクションスクリプトはビットコイン専用のScript言語により記述されています。このスクリプト言語は非常にシンプルな言語な複雑な処理を行うことはできません。しかしその分、軽量に動作し脆弱性を生むことを防いでいるのです。

 

チューリング不完全な言語

チューリング完全な言語であるということは、万能チューリングマシンと同じ計算能力を持つ言語であるということです。つまり、その言語で記述すればさまざまなアルゴリズムを構築することができるということです。もっと簡単にいうと普通のプログラミング言語です。チューリング完全な言語はC、Java、Javascriptなどがあげられます。

しかし、ビットコインのスクリプト言語はチューリング不完全な言語です。なので、ループやif文などの分岐処理ができないように制限されています。これにより無限ループを作るDDoS攻撃を防ぐことができるのです。

このように非常に単純な言語でもトランザクションスクリプトは実行できるということです。

 

ステートレス

スクリプト言語のもうひとつの重要な性質としてステートレスであることがあげられます。つまり、スクリプト言語がトランザクションスクリプト実行ごとの情報を保持しないということです。

なので、トランザクションスクリプトの実行に必要な情報は全てトランザクションスクリプト自体に保存されているということになります。

 

そこで、具体的にトランザクションスクリプトがどのように実行されているのか見ていきましょう。トランザクションでは、scriptSigとscriptPubKeyという2種類のスクリプトによって成り立っています。

 

ScriptPubKeyとScriptSig

トランザクションスクリプト

トランザクションスクリプトとは、「トランザクションが正しく実行されているかチェックするプログラム」でした。そして、トランザクションはインプットとアウトプットから成っているとお伝えしました。

上図のようにアウトプットにおける条件指定がScriptPubKeyであり、インプットにおける条件解除がScriptSigになります。

 

まず、ScriptPubKeyはlocking scriptとも呼ばれアウトプットで使用する条件を指定します。例えば、ScriptPubKeyによってビットコイン送信先のアドレスを指定します。

続いて、ScriptSig(unlocking script)でインプットでの条件を解除します。これによりアウトプットで再度UTXOが使用できるようになるのです。アウトプットで条件をロックし、その条件をインプットでアンロックすると考えると理解しやすいかもしれません。

このようにトランザクションスクリプトでは、ScriptSigでUTXOを再利用できるように役割を解放して、ScriptPubKeyによってUTXOの再度役割を決めているのです。そして、ScriptPubKeyによってロックされたUTXOはUTXOプールに保存されます。UTXOプール自体はノードのローカルメモリあるいは永続的なストレージのデータベースに保存されています。

また、ビットコインのトランザクション自体の構造は以下のようになっています。

ビットコイントランザクション

少し抽象的な解説になってしまったので、ここからは具体的なトランザクションスクリプトの種類を見ていきましょう。

 

トランザクションスクリプトの種類

ビットコインのトランザクションスクリプトは現在以下の5種類存在しています。

  • P2PKH(Pay to Public Key Hash)
  • P2PK(Pay to Public Key)
  • マルチシグネチャ(Multi-Signature, マルチシグ)
  • P2SH(Pay to Script Hash)
  • OP_RETURN(データアウトプット)

 

P2PKH(Pay to Public Key Hash)

P2PKHは最も一般的なスクリプトで、ビットコインネットワーク上で処理されているトランザクションの多くはP2PKHトランザクションです。

アリスがボブに10BTCを送金する状況を考えます。簡略化のためアリスのアドレスは10BTCのUTXOを持っていて取引手数料は考えないことにします。

まず最初に、このUTXOはアリスのアドレスにロックされているためscriptSigによってロックを解除します。scriptSigでロックを解除するためにはアリスの秘密鍵によって署名し公開鍵を添付する必要があります。

次にボブに送金するためにscriptPubKeyでボブのアドレスにロックします。これによりアリスの10BTCのUTXOはボブのアドレスに紐付けられましたので送金が完了したことになります。

 

送金をするときはアンロック→ロックの順で実行することになります。

つまり、scriptSig(unlocking script)で送り手のデジタル署名と公開鍵を提示することで条件を解除することができるというわけです。署名は秘密鍵によって作られ、その秘密鍵は送り手しか保持していないため、scriptSigで条件を解除できるのは送信先のみになります。

そしてP2PKHは送金先をビットコインのアドレスに指定したスクリプトになります。要は、P2PKHの場合、上述したscriptPubKey(locking script)の条件がビットコインアドレスに指定されているということなのです。

 

ややこしいのでアリスとボブの例で繰り返しますが、アリスが送金をするためにはまずUTXOが持っているアリスのアドレスをアンロックする必要があります。このアンロックはscriptSigでアリスのデジタル署名と公開鍵を用いて実行されます。

続いて、この自由になったUTXOをボブのアドレスにロックします。このロックはscriptPubKeyでボブのアドレスを用いて実行されるのです。これで元々アリスのUTXOがボブにロックされたことになりまうす。もし、さらにボブがこのUTXOを第三者チャーリーに送りたい場合は、再びscriptSigでボブのデジタル署名と公開鍵を用いて条件を解除(アンロック)し、scriptPubKeyでチャーリーのアドレスを用いて条件付け(ロック)します。

 

P2PKHに必要な情報ををまとめると以下のようになります。

  • scriptPubKey:送信先のアドレス
  • scriptSig:送信元のデジタル署名と公開鍵

また、以下の記事でお伝えしているようにビットコインのアドレスは公開鍵をハッシュ関数に渡すことで作られています。

参考:秘密鍵から公開鍵そしてアドレスが生成されるまでの流れ【仮想通貨】

 

P2PK(Pay to Public Key)

P2PKは前述のP2PKHをシンプルにしたスクリプトで、scriptPubKeyの条件付けにビットコインアドレス(公開鍵ハッシュ)を用いるのでなく、単に公開鍵そのものを用いる形式です。

また、scriptSigの条件解除もデジタル署名だけで行われ、公開鍵は必要とされません。ビットコインアドレス形式の方が短く分かりやすいので、P2PKHは現在ほとんど使用されていません。

  • scriptPubKey:送信先の公開鍵
  • scriptSig:送信元のデジタル署名

 

マルチシグネチャ(Multi-Signature, マルチシグ)

マルチシグネチャとは、scriptPubKeyでの条件付けとscriptSigでの条件解除にそれぞれ複数の公開鍵とデジタル署名を必要とするスクリプトです。

よく「2-of-3マルチシグ」と表現され、この場合は3つの公開鍵で条件付けされ、そのうちの2つ以上のデジタル署名を使わなければ条件解除ができないということです。

M-of-Nマルチシグネチャに必要な情報は以下のようになります。

  • scriptPubKey:N個の送信先の公開鍵
  • scriptSig:M個の送信元のデジタル署名

 

P2SH(Pay to Script Hash)

P2SHは比較的新しく登場(2012年)したスクリプトでマルチシグネチャの改良版です。マルチシグネチャの場合は、送り手が特別なスクリプトを実行し、多くの手数料を支払う必要がありました。

一方、P2SHでは「N個の送信先の公開鍵」をハッシュ関数に渡したハッシュ値に指定するだけでscriputPubKeyが実行できるようになりました。これにより、送信者は通常の送金のようにアドレスを指定するだけでマルチシグネチャと同じスクリプトを実行できます。

複雑な処理のスクリプトは受け手、つまりインプット側で実行することになるので送り手の取引手数料を抑えることも可能になったのです。この複雑な処理はredeem scriptに存在し、N個の送信先の公開鍵の情報を含みます。

M-of-N P2SHに必要な情報は以下の通りです。

  • scriptPubKey:送信先の1つのアドレス
  • scriptSig:M個の送信元のデジタル署名とredeem script

 

OP_RETURN(データアウトプット)

OP_RETURNは少し特殊なトランザクションスクリプトでビットコインの送金以外のために使われるスクリプトになります。例えば、トランザクションのタイムスタンプを参照することによるファイルの存在証明などがあげられます。この場合、トランザクションの送金額は0BTCです。

従来のP2PKHなどでこのトランザクションを実行してしまうとUTXOデータベースの肥大化につながってしまうので、その対策としてOP_RETURNが実装されました。つまり、0BTCのトランザクションを実行するためのトランザクションスクリプトがOP_RETURNです。

 

なぜ、0BTCのトランザクションはUTXOデータベースの肥大化につながってしまうのでしょうか。まず、UTXOがトランザクションアウトプットから新たに生成されるとUTXOプールというメモリに保存されます。UTXOプールはビットコインネットワークの各ノードが保持していて、トランザクション時に有効なUTXOを素早く探すために存在するのです。

しかし、UTXOの持っているビットコインが0BTCだと二度とトランザクションインプットに使われず、永遠とUTXOプールに溜まってしまうのです。これにより、UTXOデータベースの肥大化が起きてしまいます。

0BTCのトランザクションではOP_RETURNスクリプトを使用することで、UTXOをUTXOプールに格納しないようにしています。