ビットコインは、
プログラマブルマネーと呼ばれることもあります。デジタルであるため、ユーザーは資金の使途条件を非常に柔軟に設定することが可能です。
ビットコインを議論する際、私たちは
ウォレットと
通貨のことを話します。しかし、ウォレットは鍵、通貨は小切手、
ブロックチェーンはロックされた金庫の列のように考えることもできます。各金庫には薄いスロットがあり、誰でも小切手を預けたり、金庫の価値を詮索したりすることができます。ただし、内部にアクセスできるのは鍵の保持者のみです。
鍵の保持者が誰かに資金を送金するとき、彼らは自分の金庫の鍵を開けます。彼らは古い小切手を参照して新しい小切手を作成し(これは破棄されます)、受取人が開けることのできる金庫に鍵をかけます。それを使用するために、新しい受取人はこのプロセスを繰り返します。
この記事では、ビットコインネットワーク上の
ノードが解釈するプログラミング言語であるスクリプトについて詳しく見ていきます。スクリプトは、金庫のために言及されたロック/ロック解除のメカニズムを管理するものです。
上記の例えで言うと、すべてのトランザクションにはキー(ボックスのロックを解除するには)とロックという2つの部分があります。あなたは、送信したい小切手が入っているボックスを開けるために鍵を使用し、新しい小切手を別の鍵のかかった新しいボックスに追加します。新しいボックスから資金を使用するには、別の鍵が必要です。
実にシンプルです。また、システム内のロックのタイプについても多少のバリエーションを得ることができます。
複数のキーを用意する必要がある金庫もあれば、秘密を知っていることを証明する必要がある金庫もあります。ユーザーが設定できる条件はたくさんあります。
キーはscriptSig、ロックはscriptPubKeyと呼ばれています。これらのコンポーネントをもう少し詳しく見てみると、実際にはデータの一部とコードのブロックで構成されていることがわかります。これらを組み合わせて小さなプログラムを作成しています。
トランザクションを行うと、その組み合わせをネットワークにブロードキャストすることになります。それを受信した各ノードは プログラムをチェックし、トランザクションが有効かどうかを判断します。有効でなければ破棄され、ロックされた資金を使用することはできません。
保有している小切手(通貨)は、
未使用トランザクションアウトプット(UTXO)と呼ばれています。この資金は、錠前に合う鍵を提供できる人なら誰でも利用できます。具体的に、キーはscriptSig、ロックはscriptPubKeyです。
UTXOがウォレットの中にある場合、おそらく、
この公開鍵の所有権を証明できる人のみ、この資金のロックを解除することができます。資金のロック解除をするには、scriptPubKeyで指定された公開鍵に対応する
秘密鍵を使用して、
デジタル署名を含むscriptSigを指定します。これらはすぐに明らかになるでしょう。
スクリプトはスタックベースの言語として認識されています。つまり、一連の条件を読む際、それを縦の列と考えられる場所に配置します。例えば、A、B、Cというリストは、最下部がA、最上部がCのスタックになります。条件が指示すると、スタックの先頭から始まる1つ以上の要素を操作します。
要素 A、B、Cが追加され、スタックから“ポップ”されます。
データ(
署名、
ハッシュ、公開鍵など)と条件(または
オペコード)を区別することができます。指示によってデータが削除され、何らかの処理が行われます。ここでは、スクリプトの簡単な例を次に示します。
<xyz> <md5 hasher> <d16fb36f0911f878998c136191af705e> <check if equal>
赤がデータ、青がオペコードです。左から右に読み込んでいくので、最初に文字列<xyz>をスタックに置きます。次に<md5 hasher>オペコードです。これはビットコインには存在しませんが、スタックの一番上の要素(<xyz>)を削除し、MD5アルゴリズムを使用してハッシュするとしましょう。そして、出力はスタックに追加されます。ここでの出力はd16fb36f0911f878998c136191af705eです。
次に追加する要素は <d16fb36f0911f878998c136191af705e>なので、このスタックには同じ要素が2つあります。最後に、<check if equal>は2つの要素を上からポップして、それらが等しいかどうかをチェックします。等しければ、スタックに <1>を追加します。そうでない場合は、<0>を追加します。
これで条件リストが終了しました。このスクリプトは2つの要因で失敗する可能性があります。残りの要素がゼロであった場合、または演算子のいずれかが条件を満たさなかった場合、失敗する可能性があります。この例では、そのような演算子はありませんでしたが、ゼロではない要素(<1>)で終了しため、スクリプトは有効でした。これらのルールは、実際のビットコイン取引にも該当します。
これは単なる例えのプログラムです。では、実例をいくつか見てみましょう。
Pay-to-Pubkey(P2PK)は信じ難いほど簡単です。これには、特定の公開鍵に資金をロックすることが含まれています。この方法で資金を受け取りたい場合は、ビットコインのアドレスではなく、自分の公開鍵を送信者に提供することになります。
2009年に
サトシ・ナカモトとハル・フィニー氏の間で行われた
最初の取引はP2PKでした。ビットコインの黎明期にはこの構造が多用されていましたが、現在ではPay-to-Pubkey-Hash(P2PKH)に置き換えられています。
P2PKトランザクションのロックスクリプトは、 <public key>OP_CHECKSIGの形式に従います。OP_CHECKSIG は提供された公開鍵に対する署名をチェックします。そのため、scriptSigは単純な<signature>となります。scriptSigはロックの鍵であることに注意してください。
これほどシンプルなものはありません。署名がスタックに追加され、その後に公開鍵が追加されます。OP_CHECKSIGは両方をポップし、公開鍵と署名を照合します。一致する場合、スタックに<1>を追加します。そうでない場合は、<0>が追加されます。
次のセクションで詳しく説明しますが、P2PKは既に使用されていません。
Pay-to-Pubkey-Hash (P2PKH) は現在、最も一般的なトランザクションのタイプです。古いソフトウェアをダウンロードしない限り、ご使用のウォレットはデフォルトでダウンロードされていると思います。
P2PKHのscriptPubKeyは以下の通りです:
OP_DUP OP_HASH160<public key hash>OP_EQUALVERIFY OP_CHECKSIG
scriptSigを紹介する前に、新しいオペコードの動作を説明していきます。
OP_DUP
OP_DUPは最初の要素をポップし、それを重複します。次に、両方をスタックに追加します。通常は、オリジナルの要素に影響を与えずに重複を操作できるようにします。
OP_HASH160
これは最初の要素をポップして、それを2回ハッシュします。最初の段階では、SHA-256アルゴリズムでハッシュします。次にSHA-256出力がRIPEMD-160アルゴリズムでハッシュされます。結果の出力はスタックに追加されます。
OP_EQUALVERIFY
OP_EQUALVERIFYは、OP_EQUALとOP_VERIFYという2つの演算子を組み合わせたものです。OP_EQUALは2つの要素をポップし、それらが同一かをチェックします。同一であればスタックに1を追加し、そうでない場合は、0を追加します。OP_VERIFYは先頭の要素をポップし、それがTrue(すなわち、0ではない)かどうかをチェックします。そうでない場合、トランザクションは失敗します。OP_EQUALVERIFYを組み合わせ、先頭の2つの要素が一致しない場合にもトランザクションは失敗します。
今回のscriptSigは以下の通りです:
<signature><public key>
P2PKH出力のロックを解除するには、署名と対応する公開鍵を提供する必要があります。
上記のGIFをご覧の通り、これはP2PKスクリプトと大部分が同様で公開鍵がスクリプト内のハッシュと一致しているかを確認するためのステップを追加しています。
しかし、注意すべき点があります。P2PKHロックスクリプトでは、公開鍵は表示されず、ハッシュのみが表示されます。
ブロックチェーンエクスプローラで、使用されていないP2PKHの出力を見ても、公開鍵を判断することはできません。それが明らかになるのは、受信者が送金を決定した場合のみとなります。
これには2つの利点があります。1つ目は、公開鍵ハッシュは完全な公開鍵よりも簡単にやり取りできるということです。サトシが2009年に発表したのは、まさにこのような理由からです。公開鍵ハッシュは、現在ビットコインアドレスとして認識されているものです。
2つ目の利点は、公開鍵ハッシュが
量子コンピューティングに対するセキュリティの追加レイヤーを提供してくれる可能性があることです。公開鍵は資金を使用するまで明らかにされないので、他の人が秘密鍵を計算するのはさらに困難です。秘密鍵を入手するには、2回のハッシュ(RIPEMD-160とSHA-256)を逆にしなければならないでしょう。
Pay-to-Script-Hash(P2SH)は、
ビットコインにとって非常に興味深い開発でした。これにより、送信者はスクリプトのハッシュに資金をロックすることができます。スクリプトの実際の動作を知る必要はありません。以下のSHA-256ハッシュを使用します。
e145fe9ed5c23aa71fdb443de00c7d9b4a69f8a27a2e4fbb1fe1d0dbfb6583f1
資金をロックするためにハッシュの入力を知る必要はありません。ただし、支出者はハッシュに使用したスクリプトを提供し、そのスクリプトの条件を満たす必要があります。
上記のハッシュは以下のスクリプトから作成されました:
<multiply by 2> <4> <check if equal>
scriptPubKeyに関連付けられた通貨を使用したい場合は、それらのコマンドを提供するだけではありません。完成したスクリプトをTrueと評価するscriptSigも必要です。この例では、<multiply by 2>の結果を得るために<4> を乗算する要素がこれにあたります。もちろん、これはscriptSigが<2>であることを意味します。
実際には、P2SH出力のscriptPubKeyは以下のようになります:
OP_HASH160 <redeemScript hash> OP_EQUAL
ここには新しい演算子はありません。しかし、新しい要素として<redeemScript hash>があります。その名が示すように、これは資金を換金するために必要なスクリプトのハッシュです(redeemScriptと呼ばれます)。scriptSigは、redeemScriptに何が含まれているかによって変化します。しかし、一般的には、署名と添付の公開鍵の組み合わせで、redeemScript(必須の)が続きます:
<signature> <public key> <redeemScript>
私たちの評価は、これまでご覧になったスタック実行とは少し異なり、2つの部分に起こります。最初のステップでは、単に正しいハッシュを指定したかどうかをチェックします。
redeemScriptの前にある要素については何も行われていないことに注意してください。この時点では、これらの要素は使用されていません。このミニプログラムの最後に到達し、一番上の要素は0以外の値になっています。これは有効であることを意味します。
しかし、まだ終わっていません。ネットワーク
ノードはこの構造体をP2SHと認識するため、実際にscriptSigの要素が別のスタックで待機しています。そこで署名と公開鍵が使用されます。
これまではredeemScriptを要素として扱ってきました。しかし、これからは指示として解釈されます。P2PKHロックスクリプトの例を見てみましょう。このスクリプトには<signature>と<public key>に一致する<public key hash>と<redeemScript>を指定する必要があります。
redeemScriptが展開されると、通常のP2PKHトランザクションと全く同じような状況になっていることがわかります。そこからは、通常の方法で実行します。
我々はP2SH(P2PKH)スクリプトと呼ばれるものをデモしましたが、実際に使用されることはほとんどありません。ブロックの作成を妨げるものはありませんが、追加の利点はなく、ブロック内でより多くのスペースを占有することになります(そのため、コストが高くなります)。
P2SHは通常、
マルチシグネチャや
SegWit互換のトランザクションなどに有用です。複数の鍵を必要とする場合があるため、Multisigトランザクションのサイズは非常に大きくなる可能性があります。Pay-to-Script-Hashを実装する前に、送信者はロックスクリプト内に公開鍵をすべてリストアップしなければなりませんでした。
しかし、P2SHでは、支出条件がどれだけ複雑であっても問題ありません。redeemScriptのハッシュは常に固定サイズです。そのため、コストはロックスクリプトのロックを解除したいユーザに渡されます。
SegWitとの互換性は、P2SHが有用なもう1つのケースです(トランザクション構造の違いの詳細については、次のセクションで説明します)。SegWitはソフトフォークによってブロック/トランザクション形式が変更されました。これはオプトインアップグレードなので、すべてのウォレットソフトウェアが変更を認識するわけではありません。
顧客がSegWitスクリプトのハッシュをP2SHでラップしていても、それは問題ではありません。このタイプのすべてのトランザクションと同様に、クライアントはロック解除されたredeemScriptが何であるかを知る必要はありません。
SegWitのトランザクション形式を理解するには、もはやscriptSigとscriptPubKeyだけではないことを認知しておく必要があります。今では、証人と呼ばれる新しい分野も存在します。scriptSigに保持していたデータは証人に移動され、scriptSigは空になります。
そして、bc1で始まるアドレスは、SegWitネイティブと呼ばれているものです(これはP2SHアドレスなので3で始まるSegWit互換ではありません)。
Pay-to-Witness-Pubkey-Hash(P2WPKH)
Pay-to-Witness-Pubkey-Hash(P2WPKH)はP2PKHのSegWit版です。証人はこのような感じになります:
<signature><public key>
これは P2PKHのscriptSigと同様であることに注意してください。ここではscriptSigは空です。一方、scriptPubKeyは以下のようになっています:
<OP_0><public key hash>
少し違和感を感じますね。署名、公開鍵、そのハッシュを比較するためのオペコードはどこにあるのでしょうか?
トランザクションを受け取るノードは、<public key hash>の長さに基づいてそれをどうするか認識しているので、ここでは追加の演算子を表示していません。彼らは長さを計算し、古き良き時代のP2PKHトランザクションと同様なスタイルで実行しなければならないことを理解しています。
アップグレードされていないノードは、そのような方法でトランザクションを解釈する方法を知りませんが、問題はありません。古いルールでは、証人がいないので、空のscriptSigといくつかのデータを読み込みます。彼らはこれを評価し、それを有効とマークします。彼らが懸念している限り、誰でも出力を使用することができます。これがSegWitが下位互換の
ソフトフォークとみなされる理由です。
Pay-to-Witness-Script-Hash(P2WSH)
Pay-to-Witness-Script Hash(P2WSH)は新しいP2SHです。ここまで読んでいただいた方は、おそらくこれがどのように表示されるかを理解していると思いますが、一旦説明します。証人は通常scriptSigに入れるものです。例えば、P2PKHトランザクションをラップするP2WSHでは、以下のようになります:
<signature 1><public key>
これがscriptPubKeyです:
<OP_0><script hash>
同じルールが適用されます。SegWitノードはスクリプトハッシュの長さを読み、それがP2WSH出力であると判断し、P2SHと同様に評価されます。一方、古いノードはそれを誰でも自由に使用できる出力と見なします。
この記事では、ビットコインの構成要素について少し学んできました。要約してみましょう。
スクリプトタイプ | 説明 |
---|
Pay-to-Pubkey(P2PK) | 特定の公開鍵に資金をロック |
Pay-to-Pubkey-Hash(P2PKH) | 特定の公開鍵ハッシュ(アドレス)に資金をロック |
Pay-to-Script-Hash(P2SH) | 受信者が提供できるスクリプトのハッシュに資金をロック |
Pay-to-Witness-Pubkey-Hash(P2WPKH) | P2PKのSegWitバージョン |
Pay-to-Witness-Script-Hash(P2WSH) | P2SHのSegWitバージョン |
ビットコインを深く掘り下げてみると、なぜビットコインがこれほどまでに大きな可能性を秘めているのかが理解できるようになります。トランザクションは、様々なコンポーネントで構成できます。これらのビルディングブロックを操作することにより、ユーザーは資金をいつどのように使用できるかの条件を非常に柔軟に設定することができます。