前々回記事(#0):10分でわかった気になるBitcoinとBlockchain
前回記事(#1): 猿でも出来るBitcoin送金ハンズオン
前回記事ではハンズオン中心に技術的な話には触れませんでしたが、今回から2回かけてチビっとだけ技術的な説明にトライします。
まぁ僕の理解自体が「良いかげん」ですので、一緒に調べながら技術を楽しみましょう
なお次回記事(#3)では今回説明しないBlock・マイニング・PoWなどの説明を予定しています。
AGENDA
- ハッシュ関数・公開鍵暗号方式・電子署名
- Bitcoinアドレス
- UTXO
- Transactionの構造
- 送金処理
1.ハッシュ関数・公開鍵暗号方式・電子署名
前々回、前回の説明で、ハッシュ関数・公開鍵暗号方式・電子署名ってのが出てきました。
なーんとなく分かってるつもりでいるけど、人に説明するのって難しいですよね
Bitcoin, Blockchainのもっとも基本的な基礎技術なので、ちょっと復習しておきましょう。
参考サイト
ビットコインに使われている暗号化技術を解説|なぜ暗号化が必要なの?
(1)ハッシュ関数
参考サイトからのパクリ引用です
暗号学的ハッシュ関数とは簡単に言うと、任意の長さの文字列を入力すると一定のサイズのランダムな数値を返すような関数です。この一定のサイズのランダムな値をハッシュ値と呼びます。暗号学的ハッシュ関数は出力された数値から、元のメッセージに復号化することは出来ません。
どんなものかちょっとハッシュ計算をやってみましょう。
ハッシュ関数にはいろんな種類がありますが、Bitcoinでよく使われるのはSHA256(SHA2 256bit)です。
Macだとshasumコマンドを使ってこんな感じになります。1文字変更しただけでまったく異なるハッシュ値になっています。
Mac持ってない方は、以下のようなWebサイトでも確認できます。このサイトはメジャーなハッシュ関数の結果が同時に得られます。
http://www.blockchain-basics.com/HashFunctions.html
(2)公開鍵暗号方式
ITの世界で言う「暗号方式」ってのは、あるデータを「鍵」を使ってごにょごにょして意味不明なデータに変換(暗号化)し、「鍵」を知っている人が、その暗号化データから元データを復元する(復号化)っていう、その「ごにょごにょ」の方式です。元データのことを「平文」、暗号化データを「暗号文」と言ったりします。
その暗号方式の1つである公開鍵暗号方式は「非対称暗号方式」とも呼ばれます。「非対称」ってことは「対称」があるってことで、この「対称」の方は「共通鍵暗号方式」と呼ばれます。
この「共通鍵暗号方式」は「鍵配送問題」という根源的な課題があります。
復号して欲しい人に事前に鍵を届けておく必要がある、その「鍵の配送」をどうやって安全に行うか?という課題です。平文を安全に届けるための暗号方式なのに、そのための鍵を安全に届ける方法が課題って面白いですよね。
で、この鍵配送問題を解決するのが「非対称暗号方式=公開鍵暗号方式」です。
暗号化と復号化に同じ鍵使っている(対称)から鍵配送問題が起こる訳で、違う鍵を使えば(非対称)良い訳です。うーん、もっとも論を言うのはすごく簡単
・図の例:
- 送信者(Aさん)が、鍵ペア・秘密鍵と公開鍵を作成します。
- Aさんは受信者(Bさん)に自分の公開鍵を送っておきます(誰でも見れるよう公開しておいてもOKです)。
- Aさんは自分の秘密鍵を使って暗号文を作成します。
- Aさんは作成した暗号文をBさんに送ります。
- BさんはAさんの公開鍵で暗号文を復号化します。
あれっ?この例では誰でも暗号文を復号化して見れますね?(Aさんの公開鍵が公開されている場合)
はい、これは元データが確かにAさんによって暗号化されているっていう証明に使う方法なんです。
二人の秘密にしたいデータを送る時は以下のようにします。
- 受信者(Bさん)が、鍵ペア・秘密鍵と公開鍵を作成します(図では暗号キーと復号キー)。
- Bさんは送信者(Aさん)に自分の公開鍵を送っておきます(誰でも見れるよう公開しておいてもOKです)。
- AさんはBさんの公開鍵を使って暗号文を作成します。
- Aさんは作成した暗号文をBさんに送ります。
- Bさんは自分の秘密鍵で暗号文を復号化します。
Bさんの秘密鍵を知っているのはBさんだけなので、元データを二人の秘密にできます
(3)電子署名
電子署名とは、文書への押印やサインを行う行為とよく似た機能を持つ公開鍵暗号技術です。
電子署名の機能は電子的なメッセージに対して、
「そのメッセージの作成者は誰か」「そのメッセージが1ビットも改ざんされていない」
という2つを証明することが出来ます。
そしてこの電子署名を作成する人を「署名者」と呼びます。署名者はメッセージと自分の秘密鍵を使って固有の電子署名のデータを作成します。この計算を署名作成と呼びます。
この電子署名を利用して、メッセージの完全性などを検証するのは第三者で、「署名検証者」といいます。この署名検証者は、メッセージと電子署名に対して署名作成者の公開鍵を使った計算によって電子署名の検証を行います。この計算を署名検証と呼びます。
以下の図にあるように、元データ(文書)・署名者の公開鍵・電子署名の3点があると、その「電子署名文書」を署名したのが、署名者であることが検証できます。
Wiki:電子署名にある図
2.Bitcoinアドレス
Walletは、まず乱数を発生させて「秘密鍵」を作り、それからペアとなる「公開鍵」を作ります。Bitcoinアドレスはこの「公開鍵」から作成されます。
もちっと詳しく:ビットコインアドレス生成のロジック
上はMainnetの一般的なアドレス形式(P2PKH: Pay to Public Key Hash)の場合で、「5.先頭に0x00入れて」はVersion Prefix (Version Byte)と呼ばれます。Bitcoinアドレスには他の形式もあり、MainnetとTestnetのBitcoinアドレスもこれで分けられています。
アドレス形式 | Version Prefix | Bitcoinアドレスの先頭 |
---|---|---|
P2PKH(Mainnet) | 0x00 | 1 |
P2PKH(Testnet) | 0x6F | m or n |
P2SH(Mainnet) | 0x05 | 3 |
P2SH(Testnet) | 0xCF | 2 |
3.UTXO
さて、Bitcoinアドレスの「残高」ですが、普通に考えると「Aさんアドレス:Aさん残高」のような口座残高方式で保持できそうですが、BitcoinではUTXOと呼ぶ自分宛てのTransactionを集計する方法を採用しています(ちなみにEthereumは口座残高方式です)。
参考:UTXO
UTXOとは、「Unspent Transaction Output」の略で、日本語では「未使用トランザクションアウトプット」などと呼ばれています。これは簡潔に言えば、通帳のようにアカウントの残高をそのままデータとして管理・記録するのではなく、取引データのみに基いて残高を計算して求める方法です。
Transactionには次章で説明するように「誰から・いくら来たか、誰に・いくら送るか」の情報が含まれます。
ちょっとホリエモンさんのBitcoinアドレスをExplorerで覗いてみましょう。
https://live.blockcypher.com/btc/address/1G2jt5WeGhqWtDKEkcKY2GrZKjfYsuiVxX/
左側が「誰から・いくら来たか」で、右側の2つが「誰に・いくら送るか」です。右側の上は(spent)、下は(unspent)となっていて、(unspent)のアドレスは自分のアドレスです。
上の(spent)はすでに誰かに送っていて自分ではもう使えませんが、下の自分に送ったものはまた使えます(unspent)。80円の支払い(spent)に、持っていた100円で支払って20円のお釣り(unspent)が返ってくるようなイメージです。
ちなみに、80円の支払い(spent)に、持っていた100円で支払って「お釣りはいいよ」っていったどうなるでしょう?
Bitcoinでは IN(100円)-OUT(80円)が「手数料(20円)」としてマイナーに支払われます。
ホリエモンさんのTransaction例だと、以下が手数料です。
0.01859968 - (0.00358838 + 0.015) = 0.0000113
マイナーは手数料の多いTransactionを優先してBlockに取り込んでマイニングします。つまり手数料の多いTransactionは早めにBlockchainに書き込まれます。
チップが多いとサービスが良いって感じで、ここもインセンティブが効いています
この(unspent)を、UTXO(Unspent Transaction Output)と呼び、このUTXOの合計がそのBitcoinアドレスの「残高」になります。
4.Transactionの構造
Transactionには複数の入力(使えるUTXO)と、複数の出力(誰にいくら送るか)を指定する以下のような構造になっています。
このデータ構造で、以下のようなTransaction間のINPUTとOUTPUTの関係を表現できるようになっています。
5.送金処理
前々回にこんなざっくり説明をしました。
送金者(Aさん)が自分のUTXOを送金額+手数料分集めてINPUTにセットし、受領者(Bさん)のBitcoinアドレスと送金額をOUTPUTにセットします。
このOUTPUT側には受領者のBitcoinアドレスをセットしています(scriptPubKey)。
INPUT側には、対象UTXOの識別子(Transaction ID)と自分の電子鍵で作った署名データと自分の公開鍵をセットします(scriptSig)。
これって何やってんでしょう??
これはAさんが作成したTransactionを受け取ったNodeに、そのTransactionを「検証」してもらうためのデータ設定なんです。
さっき出てきた以下図で考えましょう(説明上手数料は0とします)。
・INPUT#0
データ項目 | 設定値 |
---|---|
トランザクションハッシュ | UTXO1のTransaction ID |
出力番号 | 0から始まる連番、最初なので0 |
署名スクリプト | Aさんの公開鍵と自分の秘密鍵で作成する署名データ |
署名対象データは署名スクリプトを除いたTransactionデータ全体です。
・OUTPUT#0
データ項目 | 設定値 |
---|---|
出金学 | 3BTC |
出金先を示すスクリプト | BさんのBitcoinアドレス |
・OUTPUT#1
データ項目 | 設定値 |
---|---|
出金学 | 2BTC |
出金先を示すスクリプト | AさんのBitcoinアドレス |
このTransactionを受け取ったNodeは以下のような検証を行ないます。
・INPUT#0の署名スクリプト内の公開鍵からAさんBitcoinアドレスの確認
・INPUT#0の署名スクリプト内の署名データ・公開鍵から、このTransactionがAさんによって作成されたことの確認(電子署名は、署名データ・公開鍵・元データがあれば検証できることを思い出しましょう。)
言い換えると各Nodeが行う検証とは、このTransactionは、間違いなくAさんが、Aさん宛てのUTXO(5BTC)を使って、Bさん(3BTC)とAさん(2BTC)に送金しようとしているってことの確認です。
Nodeは検証OKであれば、送信元にOK返信して他のNodeにそのTransactionを転送しますので、転送と検証を繰り返してTransacrionは全P2Pネットワークに伝搬されます。
検証NGの場合は、Nodeは送信元にNG返信して転送は行いません。このため不正なTransactionによる攻撃をうけてもDOS耐性があります。
電子署名を使って、自分宛てのUTXO(残高)をロック解除して、送金先・送金金額をロックするってのが、WalletがやっているTransaction作成なんですねー。すっごく面白い!!
でも、この検証だけだと、Aさんが同じUTXO1(5BTC)を別のCさんに送金する署名検証OKなTransactionも作成できますよね(二重支払い問題)。
次回はこの二重支払い問題を解決するBlockchainについて説明します。
Enjoy