前回
Bitcoin Coreを触りながらBitcoinについて理解する - その1(構築~アドレス生成まで)
からの続きです。
7.UTXOとトランザクションスクリプト
7-1.『BTCを送付する』ということ
前回、ビットコインアドレスを指定してBTCを送付することができるという概念について学んだ。今回はそれを具体的にどのようにブロックチェーン上で実現しているのか見ていきたい。
実際にトランザクションをウォッチしながら考えてみた。
適当にトランザクションを一つ取り出してみる。下記に表示しているのはblock height=123456
ブロックのindex=1
(上から2番目)のトランザクションだ。(適当に選んだだけなので他意はない)
$ ./gettx.sh e3d0425ab346dd5b76f44c222a4bb5d16640a4247050ef82462ab17e229c83b4
{
"txid": "e3d0425ab346dd5b76f44c222a4bb5d16640a4247050ef82462ab17e229c83b4",
"hash": "e3d0425ab346dd5b76f44c222a4bb5d16640a4247050ef82462ab17e229c83b4",
"version": 1,
"size": 258,
"vsize": 258,
"weight": 1032,
"locktime": 0,
"vin": [
{
"txid": "4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54",
"vout": 1,
"scriptSig": {
"asm": "3045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c[ALL] 0449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e",
"hex": "483045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c01410449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e"
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 43.61000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 6c8de651f8b92f87ff43fb9732babec784bdb6f5 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9146c8de651f8b92f87ff43fb9732babec784bdb6f588ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"1Atyy5h4SSdqWRuS8pzxgTb4bMe7ZpdunP"
]
}
},
{
"value": 6.39000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 4f006767feebf6438aaf51ef86ae4286a1c571b9 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9144f006767feebf6438aaf51ef86ae4286a1c571b988ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"18CisDmjM1MmM1MjtqUHPgmoLhZcSJJTKD"
]
}
}
]
}
このトランザクションを作成した人をBob(ボブ)だとする。
アウトプット情報vout
によるとBobは下記2つのアドレスにそれぞれBTCを送付しているようだ。それぞれのアドレスの持ち主を便宜的にCarol(キャロル)とCharlie(チャーリー)と命名する。
1Atyy5h4SSdqWRuS8pzxgTb4bMe7ZpdunP
=Carolに43.61BTC
18CisDmjM1MmM1MjtqUHPgmoLhZcSJJTKD
=Charlieに6.39BTC
以上からこのトランザクションの合計送金額は43.61+6.39=50BTCとなる。
送金するというからには当然ながらBobは50BTC以上の原資を持っていなければならない。
それを何らかの形で証明しているのが、インプット情報vin
に記載されている内容だ。
"vin": [
{
"txid": "4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54",
"vout": 1,
"scriptSig": {
"asm": "3045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c[ALL] 0449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e",
"hex": "483045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c01410449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e"
},
"sequence": 4294967295
}
],
ここの記述内容を一言で表現すると『過去の取引においてBobがアクセス権を有する口座番号にBTCが入金されているので、この口座から支払いを行います』という意味になる。
ビットコインはあくまで取引を主体に考えるので、出金元情報が
インプット
であり、送金先情報がアウトプット
になることに注意。
具体的にはそれぞれのパラメータとして以下が対応している。
①過去の取引 →トランザクションIDとインデックス番号
txid=4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54
vout=1
(2番目のvoutを意味する)
②Bobがアクセス権を有する →デジタル署名
3045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c[ALL]
③口座番号 →公開鍵0449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e
asm
はアセンブリ言語、hex
はそれを機械語(バイナリー)に変換したもの。意味は変わらないので、特に注釈ないときはasm
を基準とする。
では実際に①で指定されているトランザクションID
4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54
を追跡してみよう。
$ ./gettx.sh 4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54
{
"txid": "4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54",
"hash": "4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54",
"version": 1,
"size": 192,
"vsize": 192,
"weight": 768,
"locktime": 0,
"vin": [
{
"txid": "aed03b8fbb969f45054472aee613c6b115320e8c1ceeb3c2f92c52f8dbc67078",
"vout": 0,
"scriptSig": {
"asm": "3045022043df36465eb8854649a62b36e8d9a402bce012267ac8f4857ef3b5ca2f3396b7022100ae120cbba78942b82304c98efecbabc8745be7b8f6358f089344a2c5efe942dc[ALL]",
"hex": "483045022043df36465eb8854649a62b36e8d9a402bce012267ac8f4857ef3b5ca2f3396b7022100ae120cbba78942b82304c98efecbabc8745be7b8f6358f089344a2c5efe942dc01"
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.08000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 a9730a07ea5626f14f7fa304c1309602b10a0553 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914a9730a07ea5626f14f7fa304c1309602b10a055388ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"1GSy1UxBx7fyNaLB55KQ2x3NpovhxsQahN"
]
}
},
{
"value": 50.00000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 4d63a4b3b4ae384c44ff5d112a9b87c4c49ff36f OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9144d63a4b3b4ae384c44ff5d112a9b87c4c49ff36f88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"184CQ7agrApMYpnKTzWnsMjV9Wx3raHw7S"
]
}
}
]
}
このトランザクションを作成した者をAlice(アリス)とする。
vout
の2番目を見ると、確かに50BTCが、とあるアドレス184CQ7agrApMYpnKTzWnsMjV9Wx3raHw7S
に送金されている。
Bobはこのアドレスが自身のものであると主張しているわけだ。このアドレスがBobのものであることをBobが証明でき、かつ誰もがそれを検証可能であるならば、BobはAliceがアドレス184CQ7agrApMYpnKTzWnsMjV9Wx3raHw7S
に送った50BTCを使用する権利があると認められる。とまあこういうロジックなわけだ。
そしてこれは容易に証明可能だ。
ビットコインアドレス
は公開鍵ハッシュ
が形を変えたものであることを既に学んだ。
公開鍵ハッシュ → (Base58Checkエンコード) → ビットコインアドレス
公開鍵ハッシュ ← (Base58Checkデコード) ← ビットコインアドレス
公開鍵ハッシュ
は公開鍵
をハッシュ化したものであるため、公開鍵
を知る者しか作成することができない。
公開鍵 → (Hash160) → 公開鍵ハッシュ
Bobは③(公開鍵)を提示しているので、③からアドレス184CQ7agrApMYpnKTzWnsMjV9Wx3raHw7S
が生成できれば、この③(公開鍵)は正しいものであることが証明される。
https://bc-2.jp/tools/txeditor2.htmlの計算ツールを使って実際に検証してみると公開鍵③が本物であることがわかるだろう。
ただし公開鍵③は一度開示されてしまえばそれまでなので、例えばマイナーによって送金先を書き換えられてしまうとどうしようもないし、同じアドレスを再利用することも出来なくなる。公開鍵③が間違いなくBobのものであることを証明するためにはどうすればいいのだろうか。
それがデジタル署名
である。デジタル署名は秘密鍵から作成し、公開鍵によって検証することを可能にするアルゴリズムである。
秘密鍵 → (ECDSA) → デジタル署名を作成
公開鍵 → (ECDSA) → デジタル署名を検証
この関係からBobは自身の秘密鍵でトランザクションにデジタル署名を付加し、他のノードが公開鍵を用いてその正当性を検証することを可能にする。
仮に正しい秘密鍵を持たない者が偽の秘密鍵で署名を作成しトランザクションを偽造したとしても、公開鍵での検証結果がNGとなり不正と判断されるので、そのようなトランザクションは間違いなくリジェクトされる。これはトランザクションを改竄から保護するということでもある。トランザクションの内容を後から他人が勝手に改竄できてしまえばオープンネットワークとしての決済システムは成り立たないので、非常に重要なポイントとなる。
以上を整理すると下図のイメージとなる。
そしてAliceのトランザクションもまた同じく、もっと過去の取引を参照している。追跡すれば、誰かからBTCを受け取っていることが確認できるはずだ。ブロックチェーンが過去のブロックへの参照の連鎖(チェーン)で出来上がっているのと同じように、トランザクションもまた過去へ過去へと遡る取引のチェーンにより成り立っているのである。
UTXO
ここで一つ大切な用語の確認をしておく。
UTXO (Unspent Transaction Output)=未使用のトランザクションアウトプット
という概念である。これは全てのトランザクションアウトプットのうち、現時点でまだ未使用のものを指している。図で言うならトランザクションID(Bob)
のVout0
,Vout1
が該当する。いずれCarolやCharlieがこれを参照するトランザクションを生成するまでこれらは永久的にUTXOであり続ける(=ロックされた状態)。一方でトランザクションID(Alice)
のVout1
はBobによって参照されたため既にUTXOではなくなっている。
一般化すると、トランザクションが新規作成されたとき、アウトプットから新たなUTXOが生み出されるが、それと同時にインプットが参照した過去のUTXOはその時点でUTXOではなくなる。言い換えればBTCの最新の所在を示すものだ。もっと分かりやすく言うと、UTXOがBTCの実体そのものと言っていい。現金であれば製造年や製造番号といった個体識別IDがあるが、BTCはそれ自体に色が付いているわけではない。その代わり、現金は個体の追跡ができないが、BTCは全ての取引がオープンになっており、今どこにどれだけのBTCが存在しているかがわかる。だからUTXOの始祖をずっと辿っていくとやがてどこかのcoinbaseトランザクションまで遡るだろう。これに例外はない。coinbase以外にBTCを生み出す源泉はないからだ。もちろん途中で途切れることはないし、失われたりもしない。coinbaseからひとたび誕生したUTXOは、形を変えながら途絶えることなく連鎖を続けていき、ビットコインネットワークのエコシステムを形作っていく。トランザクションという経済活動がもたらすこの点波源のような存在であるUTXOこそがビットコインの本質なのだ。
お釣りの回収
UTXOの特徴の一つに分割できないという規定がある。例えば50BTC入っているUTXOの中から10BTCだけ出金して残りの40BTCは残すということはできない。言い換えれば参照は一度きりしかできない仕様ということである。
そこでお釣りをどう処理するかというと下記の2パターンが考えられる。
1.元のアドレスを再利用してお釣りを振り込み、元のアドレスのまま新たなUTXOを作る。
2.お釣り用に新規アドレスを作成して振り込み、元のアドレスは使い捨てとする。
1の場合は、公開鍵がオープンになってしまっている以上、どうしてもセキュリティは下がってしまうだろう。ただしQRコードを動的に生成できない場合(紙に印刷したQRコードで広く支払いを募る場合など)は注意しながら運用していく必要がありそうである。実際のユースケースでは圧倒的に2による実装・運用がされていると思うが、いくらアドレスが作成し放題とはいえ、有限の資源であることは間違いないので将来的にはアドレス拡張を行ったりすることになるのかもしれない。
取引手数料
上記はトランザクションのインプットの総額とアウトプットの総額が同量であることを前提に話をしていたが、ではインプットとアウトプットに差がある場合はどうなるのだろうか。
アウトプットはインプットよりも多くすることはできないが、逆にアウトプットをインプットより少なく設定することはプロトコルに違反しない。この場合、アウトプットで出金されなかった差額のBTCの所有権は失うことになる。このBTCはどこに行ってしまうかというと、取引手数料の名目でcoinbaseトランザクションのアウトプットに全て加算されるように実装されている。つまり差額は採掘者へのチップとなるわけだ。
参考までに最近の手数料収入の総額はいかほどなのか、確認してみた。
下記はblock height=615758
(2020年2月3日頃)のcoinbaseトランザクション
の内容である。
./gettx.sh 1d0733ad91d14a492c6336a787787c9a6baf07c45968ac3a110755d389d04f6f
{
"txid": "1d0733ad91d14a492c6336a787787c9a6baf07c45968ac3a110755d389d04f6f",
"hash": "55e4336c1fb8820d372ca5308343b86bef1eed38555536bdd5847000b632441e",
"version": 2,
"size": 296,
"vsize": 269,
"weight": 1076,
"locktime": 0,
"vin": [
{
"coinbase": "034e65090471b3375e636430312f62797465706f6f6c2e636f6d2ffabe6d6d98e87c876f78c12807d86ac245d937241c411c25beeecba559f9c7ad9742b4b0020000004204cb9a0b8c96405ceb120000000000",
"sequence": 4294967295
}
],
"vout": [
{
"value": 12.54122895,
"n": 0,
"scriptPubKey": {
"asm": "OP_HASH160 5885ab54ce79c9384af724709edb2eb08bfa8ff7 OP_EQUAL",
"hex": "a9145885ab54ce79c9384af724709edb2eb08bfa8ff787",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"39m5Wvn9ZqyhYmCYpsyHuGMt5YYw4Vmh1Z"
]
}
},
(以下略)
12.54122895BTCが採掘者のUTXOに入金されている。
現在の採掘報酬は12.5BTCなので、差し引きすると手数料収入は0.04122895BTC=約41,228円(1BTC=1,000,000円)となる。採掘報酬と比べるとその比率は**0.32%**と僅かなものである。手数料収入が採掘報酬を上回る日が来るのはまだ当分先のようだ。
##7-2.トランザクションスクリプト
さて、ここからようやく今回の本題。
トランザクションスクリプトを理解することが当面の俄ビットコイナーの目標となるはずなので頑張っていきたい。
トランザクションスクリプトとは、前項(7-1.『ビットコインを送付する』ということ)で見てきたような概念を実際に計算機が実行できるようにするためにビットコインソフトウェアに内蔵されているプログラム言語だ。
【プログラム言語としての特徴】
・Bitcoinのために開発された専用の言語
・軽量、簡易
・Forth言語に似ている
・チューリング不完全(条件分岐、繰り返しなどの高度な処理ができない)
・スタックマシン
・逆ポーランド記法(演算子を後ろに配置する)
トランザクションスクリプトは全てのノードに評価(実行)されることを前提としており、その結果が正しい場合にトランザクションが正規のものであると認められブロックに取り込まれる。
コードはScriptPubKeyおよびScriptSigの2か所に分散しており、評価する際は結合させて使用する。
順を追って確認してみよう。
ScriptPubKey
ScriptPubKeyは"Public Key Script"(公開鍵スクリプト)の略で、別名Locking Scriptとも呼ばれる。
つまり『UTXOをロックするためのスクリプト』という意味だ。
先ほどのAliceがBobに50BTCを送付するVout部分に着目してみる。
"vout": [
(省略)
{
"value": 50.00000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 4d63a4b3b4ae384c44ff5d112a9b87c4c49ff36f OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9144d63a4b3b4ae384c44ff5d112a9b87c4c49ff36f88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"184CQ7agrApMYpnKTzWnsMjV9Wx3raHw7S"
]
}
}
ここから分かるように、ScriptPubKeyは
OP_DUP OP_HASH160 4d63a4b3b4ae384c44ff5d112a9b87c4c49ff36f OP_EQUALVERIFY OP_CHECKSIG
というプログラムコードになっている。
分解するとこんな感じ。
OP_DUP
OP_HASH160
4d63a4b3b4ae384c44ff5d112a9b87c4c49ff36f
←(以降<公開鍵ハッシュ>
とする)
OP_EQUALVERIFY
OP_CHECKSIG
説明は後ほど。
たまに誤解している記事があるが、オリジナルのブロックチェーンに載っている送金先情報はこれが全てだ。
"addresses" : 184CQ7agrApMYpnKTzWnsMjV9Wx3raHw7S
の部分はビットコインソフトウェアが人間のために補完してくれているだけであり、あくまでも記述されているのは公開鍵ハッシュ(4d63a4b3b4ae384c44ff5d112a9b87c4c49ff36f
)の方だ。
実際にはビットコインアドレスなるものはブロックチェーン上にもどこにも存在しないのである。
ScriptSig
ScriptSigは"Signature Script"(署名スクリプト)の略でUnlocking Scriptとも呼ばれる
『UTXOをアンロックするためのスクリプト』という意味だ。
BobがAliceから受け取った50BTCをインプットするVin
に着目してみる。
"vin": [
{
"txid": "4600bf5f3d49660a546c1b9acd3e6b85479ab227115f741cf12e50506ab24b54",
"vout": 1,
"scriptSig": {
"asm": "3045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c[ALL] 0449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e",
"hex": "483045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c01410449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e"
},
"sequence": 4294967295
}
],
ScriptSigは
3045022100c9e35aa55af5ac98cb67c4db7cf3d3f128753c4698f5d25ca0cdc3decd0c46be02204d6dfe89bd3fe88a32d47a44c0ab3ab60d87b27b90106f1b2f9f67c9c60cc80c[ALL]
0449b8d933f97a8c4fe6ce962ee2abff8a81d8cfc5e0870a50cea76c50d04addf2df09331c4a47cdc3bc27a628e766ef5d01f28ee147ed21723b5ff3a62ed8da3e
の部分。長いのでここでは
<デジタル署名>
<公開鍵>
の順に並んでいると理解すればOK。
スクリプトの評価
上記2つのスクリプトは対の存在になっている。
ScriptPubKeyが問題文ならば、
ScriptSigは答案といえる。
『ScriptPubKeyによってロックされたUTXOをScriptSigが正しくアンロックできるか?』
という問題と答案の組み合わせによって構成されているわけだ。
そしてスクリプトを採点(評価)するのはマイニングノードやその他のフルノードの役割となる。
具体的な処理の順序としては、ScriptSigの後ろにScriptPubKeyを結合して、スタックマシンで計算を行う。
下表の実行順1から2がScriptSig、3から7がScriptPubKeyのものだ。
|実行順|Script|処理内容|記述箇所|
|---|---|---|---|---|
|1|<デジタル署名>|データプッシュ|ScriptSig|
|2|<公開鍵>|データプッシュ|ScriptSig|
|3|OP_DUP|スタックの先頭を複製してプッシュ|ScriptPubKey|
|4|OP_HASH160|スタックの先頭をHASH160化|ScriptPubKey|
|5|<公開鍵ハッシュ>|データプッシュ|ScriptPubKey|
|6|OP_EQUALVERIFY|スタックの先頭2要素をポップし、等しければtrue|ScriptPubKey|
|7|OP_CHECKSIG|スタックの先頭2要素をポップし、順に<公開鍵>,<デジタル署名>として、署名検証。メッセージダイジェストはトランザクションのSHA260dから導出。成功ならtrue|ScriptPubKey|
最終的に評価結果がtrueとなるとき、UTXOアンロックは成功ということになる。
結局のところ、
1.Bobは正しい公開鍵を持っているか?
2.Bobは正しい秘密鍵(によって作られたデジタル署名)を持っているか?
の2点を間接的にチェックしているということだ。
ブロックチェーンを保持する全員が同じ計算方法でチェックして、『取引を承認する』というコンセンサスがネットワーク内で醸成される。
UTXOはそれ単体ではただただオープンなメモリ上に延々と放置され続けるだけの存在でしかない。誰しもが平等にアンロックを試みる機会が無制限に与えられているということだ。そこには何人の規制も介入しない。トラストレスな世界において、公衆の面前に留め置かれ常に攻撃のリスクに晒されながらも、誰一人として不正にそれを利用することができないという仕組みは非常に面白くないだろうか。
以上が最も一般的なP2PKHを用いた支払い方法だ。
#8.様々な支払い方法
理屈だけで言えばトランザクションスクリプトは当事者間で自由に記述することができる。極論すればどんなスクリプトあっても、AliceのLocking Script(問題文)とBobのUnlocking Script(答案)さえ整合すれば、それは正しい取引なのであって、BTCの送受は可能であるわけだが、万人が安心して使用できる決済プラットフォームとするためには一定のルールの存在が欠かせない。安全性や利便性を追求していく中で、これまで幾つかの支払い方法が編み出されてきた。ここではビットコインが辿ってきた歴史に沿いつつ、順に整理してみることとする。
##8-1. P2PK (Pay to Public Key)
最初期に用いられていた支払い方法。公開鍵
でロックしデジタル署名
でアンロックする。
公開鍵暗号のベーシックな使用例といえるが、公開鍵が最初からオープンになっている点がデメリット。
支払い方法 | ScriptPubKeyの要素 | ScriptSigの要素 |
---|---|---|
P2PK | 公開鍵 | デジタル署名 |
ビットコインの発明当初はこのままの内容で実装されたため、ScriptPubKeyやScriptSigという名称になったものと考えられる。
Locking ScriptやUnlocking Scriptという呼び方が今となっては圧倒的に意味が通りやすい。とはいえこれも歴史の産物だと考えると味わい深い。のだろうか?
Script | 書式 |
---|---|
ScriptPubKey | <公開鍵> OP_CHECKSIG |
ScriptSig | <デジタル署名> |
スクリプト評価フロー
実行順 | Script | 処理 | 記述箇所 |
---|---|---|---|
1 | <デジタル署名> | データプッシュ | ScriptSig |
2 | <公開鍵> | データプッシュ | ScriptPubKey |
3 | OP_CHECKSIG | スタックの先頭2要素をポップし、順に<公開鍵>,<デジタル署名>として、署名検証。メッセージダイジェストはトランザクションのSHA256dから導出。成功ならtrue | ScriptPubKey |
事例サンプル
$ ./gettx.sh 27f1d66f8a1ee5280f4e92508dcb647e954d53004905d08a75574daee4988360
{
"txid": "27f1d66f8a1ee5280f4e92508dcb647e954d53004905d08a75574daee4988360",
"hash": "27f1d66f8a1ee5280f4e92508dcb647e954d53004905d08a75574daee4988360",
"version": 1,
"size": 135,
"vsize": 135,
"weight": 540,
"locktime": 0,
"vin": [
{
"coinbase": "0415112a1c02c100",
"sequence": 4294967295
}
],
"vout": [
{
"value": 50.00000000,
"n": 0,
"scriptPubKey": {
"asm": "04a9d6840fdd1497b3067b8066db783acf90bf42071a38fe2cf6d2d8a04835d0b5c45716d8d6012ab5d56c7824c39718f7bc7486d389cd0047f53785f9a63c0c9d OP_CHECKSIG",
"hex": "4104a9d6840fdd1497b3067b8066db783acf90bf42071a38fe2cf6d2d8a04835d0b5c45716d8d6012ab5d56c7824c39718f7bc7486d389cd0047f53785f9a63c0c9dac",
"type": "pubkey"
}
}
]
}
$ ./gettx.sh 2d22e9ef36692d9f9a383523442fe6cd0439b9e8c0498f6b972845517d6d3045
(Vin抜粋)
{
"txid": "27f1d66f8a1ee5280f4e92508dcb647e954d53004905d08a75574daee4988360",
"vout": 0,
"scriptSig": {
"asm": "3045022100c68e6d5fc26175800bd3094fcd00d5b049aaaba5e47f9a276fbb18a50a2d623502200d7fc6a72cb8a6b2a9e4276a8b76e602692d36d199e45d4beaf1b2dbd3aed0ef[ALL]",
"hex": "483045022100c68e6d5fc26175800bd3094fcd00d5b049aaaba5e47f9a276fbb18a50a2d623502200d7fc6a72cb8a6b2a9e4276a8b76e602692d36d199e45d4beaf1b2dbd3aed0ef01"
},
"sequence": 4294967295
}
公開鍵がそのまま埋め込まれるので、どうしても長くなってしまう。スクリプト長が長いということはそれだけトランザクションの容量が増えるということであり、オーバーヘッドの増加につながる。
##8-2. P2PKH (Pay to Public Key Hash)
遅くとも2010年前半には既に登場していた。
ビットコインアドレス(公開鍵ハッシュ)の概念が採用されて利便性と安全性向上に寄与。
内容は散々やったので前項参照。
支払い方法 | ScriptPubKeyの要素 | ScriptSigの要素 |
---|---|---|
P2PKH | 公開鍵ハッシュ | デジタル署名, 公開鍵 |
Script | 書式 |
---|---|
ScriptPubKey | OP_DUP OP_HASH160 <公開鍵ハッシュ> OP_EQUALVERIFY OP_CHECKSIG |
ScriptSig | <デジタル署名> <公開鍵> |
スクリプト評価フロー
|実行順|Script|処理内容|記述箇所|
|---|---|---|---|---|
|1|<デジタル署名>|データプッシュ|ScriptSig|
|2|<公開鍵>|データプッシュ|ScriptSig|
|3|OP_DUP|スタックの先頭を複製してプッシュ|ScriptPubKey|
|4|OP_HASH160|スタックの先頭をHASH160化|ScriptPubKey|
|5|<公開鍵ハッシュ>|データプッシュ|ScriptPubKey|
|6|OP_EQUALVERIFY|スタックの先頭2要素をポップし、等しければtrue|ScriptPubKey|
|7|OP_CHECKSIG|スタックの先頭2要素をポップし、順に<公開鍵>,<デジタル署名>として、署名検証。メッセージダイジェストはトランザクションのSHA260dから導出。成功ならtrue|ScriptPubKey|
##8-3. Multi-Signature (BIP-011 / M-of-N Standard Transactions)
通称、マルチシグ。
N個の公開鍵でロックしM個の署名でアンロックする仕組み。
アンロックに複数の署名が必要となるため、従来の支払い方法に比べてセキュリティが高い。
支払い方法 | ScriptPubKeyの要素 | ScriptSigの要素 |
---|---|---|
Multi-Sig | N個の公開鍵 | M個のデジタル署名 |
Script | 書式 |
---|---|
ScriptPubKey | M 公開鍵1 ~ 公開鍵n N OP_CHECKMULTISIG |
ScriptSig | OP_0 デジタル署名1 ~ デジタル署名M |
スクリプト評価フロー(2 of 3 MultiSigの場合)
実行順 | Script | 処理 | 記述箇所 |
---|---|---|---|
1 | OP_0 | データプッシュ(バグ対策のWA) | ScriptSig |
2 | デジタル署名1 | データプッシュ | ScriptSig |
3 | デジタル署名2 | データプッシュ | ScriptSig |
4 | 2 | データプッシュ | ScriptPubKey |
5 | 公開鍵1 | データプッシュ | ScriptPubKey |
6 | 公開鍵2 | データプッシュ | ScriptPubKey |
7 | 公開鍵3 | データプッシュ | ScriptPubKey |
8 | 3 | データプッシュ | ScriptPubKey |
9 | OP_CHECKMULTISIG | N個の公開鍵でM個の署名を検証し、全ての署名が検証可能であればtrue。 | ScriptPubKey |
2of3の場合は、3人の公開鍵で多重ロックをかけ、そのうち2人分の署名が揃えばアンロックできる。
3者間を通じたエスクロー取引などユースケースが拡大する。
##8-4. P2SH (BIP-016 / Pay to Script Hash)
2012年頃に実装され定着している。
これもマルチシグの一種だが、BIP-011よりも以下の点でメリットがある。
・送金側のスクリプト実行コスト(取引手数料)が安い
・送金先情報を、公開鍵ハッシュ同様に、ビットコインアドレスとして表現できる。
支払い方法 | ScriptPubKeyの要素 | ScriptSigの要素 |
---|---|---|
P2SH | redeem_scriptのハッシュ | M個のデジタル署名,redeem_script |
Redeem scriptっていうのはMultiSigのアンロック部分をserializeしたもので、
BIP-011でいうScriptPubKeyの内容に相当する。
Script | 書式 |
---|---|
ScriptPubKey | OP_HASH160 redeem_script_hash OP_EQUAL |
ScriptSig | OP_0 デジタル署名1 ~ デジタル署名M redeem_script |
redeem_script | M 公開鍵1 ~ 公開鍵n N OP_CHECKMULTISIG |
スクリプト評価フロー(2 of 3の場合)
P2SHは
実行順 | Script | 処理 | 記述箇所 |
---|---|---|---|
1 | OP_0 | データプッシュ(バグ対策のWA) | ScriptSig |
2 | デジタル署名1 | データプッシュ | ScriptSig |
3 | デジタル署名2 | データプッシュ | ScriptSig |
4 | redeem_script | データプッシュ | ScriptSig |
5 | スタックの状態保存 | ||
6 | OP_HASH160 | スタックの先頭をHASH160化 | ScriptPubKey |
7 | redeem_script_hash | データプッシュ | ScriptPubKey |
8 | OP_EQUAL | スタックの先頭2要素をポップし、等しければtrue | ScriptPubKey |
9 | スタックを5に状態復元 | ||
10 | スタックの先頭をポップし、スクリプトとして実行 | ||
10a | 2 | データプッシュ | redeem_script |
10b | 公開鍵1 | データプッシュ | redeem_script |
10c | 公開鍵2 | データプッシュ | redeem_script |
10d | 公開鍵3 | データプッシュ | redeem_script |
10e | 3 | データプッシュ | redeem_script |
10f | OP_CHECKMULTISIG | N個の公開鍵でM個の署名を検証し、全ての署名が検証可能であればtrue。 | redeem_script |
見比べてみると、実際のところ、署名検証にかかる手順とコストはBIP-011と全く同じであることがわかる。
大きな違いは、本来のロックするための鍵(scriptPubKey)を外部スクリプト(Redeem script)としてscriptSig側に記述させている点である。こうすることで送金側に発生していた負担コストをまるっと受け取り側に転嫁させているわけだ。
事例サンプル
$ ./gettx.sh 5ef31625bee220e0293441b84596fcdaae9bc2a7027365175ec67d4e705f7ce6
{
"txid": "5ef31625bee220e0293441b84596fcdaae9bc2a7027365175ec67d4e705f7ce6",
"hash": "5ef31625bee220e0293441b84596fcdaae9bc2a7027365175ec67d4e705f7ce6",
"version": 1,
"size": 851,
"vsize": 851,
"weight": 3404,
"locktime": 0,
<snip>
"vout": [
{
"value": 1.00000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_HASH160 4581f8c5233637c780c40b42ac066b5e4f8255da OP_EQUAL",
"hex": "a9144581f8c5233637c780c40b42ac066b5e4f8255da87",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"382YFNmXQj3WBsK4UyUc7HfEW1vbb6jrbj"
]
}
<snip>
$ ./gettx.sh 28b8a27c0f252876c3942d7ab1d8917e418c65253543c73daef41bfb50ac8029
(vin抜粋)
"vin": [
{
"txid": "5ef31625bee220e0293441b84596fcdaae9bc2a7027365175ec67d4e705f7ce6",
"vout": 0,
"scriptSig": {
"asm": "0 3045022100c98449c7088714f7c0e503183d6a6d3c36a4811a4b99ba2112886c691c79e28a02207a136717461ed5ed68cf4ad80f2bdc083686ffc871f4d0c4d1bbd2f3f124980b[ALL] 304402207681b4c691a1ca7e4bc9150beb7cf7add6a335361794a699e49bbb63720d2c7502204a7a814a3d3b5835d0177603008ba88be193b0d51ba5ba7c23aa1b3dda900b33[ALL] 522103cfa4a57c9c016ec854187f9be5c407e4cd960b5c11bc4b87de0b77d28699273421036173cc77f927af38f0f70557833c6babdb614fdd7797135e79519203ae65d85a21026380f34fbbd8d798af3a9a63b473fac966bb78ec354b4aaef1a559baf8b15c8453ae",
"hex": "00483045022100c98449c7088714f7c0e503183d6a6d3c36a4811a4b99ba2112886c691c79e28a02207a136717461ed5ed68cf4ad80f2bdc083686ffc871f4d0c4d1bbd2f3f124980b0147304402207681b4c691a1ca7e4bc9150beb7cf7add6a335361794a699e49bbb63720d2c7502204a7a814a3d3b5835d0177603008ba88be193b0d51ba5ba7c23aa1b3dda900b33014c69522103cfa4a57c9c016ec854187f9be5c407e4cd960b5c11bc4b87de0b77d28699273421036173cc77f927af38f0f70557833c6babdb614fdd7797135e79519203ae65d85a21026380f34fbbd8d798af3a9a63b473fac966bb78ec354b4aaef1a559baf8b15c8453ae"
},
"sequence": 4294967295
},
scriptPubKeyとscriptSigの長さを見比べてみると、送金側と受け取り側のコスト差がどれほどあるか感覚的によくわかるだろう。
ちなみに、scriptPubKeyに記述されている通り、P2SHではビットコインアドレス体系は3
始まりとなる。
"addresses" : 382YFNmXQj3WBsK4UyUc7HfEW1vbb6jrbj
(P2PKHでは1
始まり)
scriptSigを見ると、
0 <デジタル署名1> <デジタル署名2> redeem_script
の並びで記述されていることがわかる。
さらにredeem_script
はdecodescript
コマンドでデコードすることができる。
$ bitcoin-cli decodescript 522103cfa4a57c9c016ec854187f9be5c407e4cd960b5c11bc4b87de0b77d28699273421036173cc77f927af38f0f70557833c6babdb614fdd7797135e79519203ae65d85a21026380f34fbbd8d798af3a9a63b473fac966bb78ec354b4aaef1a559baf8b15c8453ae
{
"asm": "2 03cfa4a57c9c016ec854187f9be5c407e4cd960b5c11bc4b87de0b77d286992734 036173cc77f927af38f0f70557833c6babdb614fdd7797135e79519203ae65d85a 026380f34fbbd8d798af3a9a63b473fac966bb78ec354b4aaef1a559baf8b15c84 3 OP_CHECKMULTISIG",
"reqSigs": 2,
"type": "multisig",
"addresses": [
"1Lf1Jb4NeF5VrLQ58Wp4drgbEbnrfHDu1A",
"1P3hp6wCYx26yfDatXdqSHJ1RqLzpPCqEV",
"152jxcp4a6bL9WViZ6v4r8ch2pENHUZM1b"
],
"p2sh": "382YFNmXQj3WBsK4UyUc7HfEW1vbb6jrbj",
<snip>
}
redeem_scriptの中身は
2 <公開鍵1> <公開鍵2> <公開鍵3> 3 OP_CHECKMULTISIG
という並びとなっている。
以上からこのscriptSigは2of3-MultiSigを実現する書式に従っていることが確認できる。
今回はここまで。
次回はSegwitに関して取り上げたい。