プログラミングのゴミ箱

日々の学習の中で知らなかったことについて、調べたことを解説します。

びっとこいんのほわいとぺーぱー

はじめに

この記事はビットコインのホワイトペーパーを読んで要点を分かりやすく解説したものです。
他にもいろんなチェーンのホワイトペーパーを出すつもりなので、気に入ったらそちらも見てくれると嬉しいです!

https://bitcoin.org/bitcoin.pdf

ホワイトペーパー

目的

ビットコインの最大の目的は二重支払い問題の解決です。二重支払い問題とは同じコインが何度も使用されてしまう問題です。
実際の世界ではお金は硬貨や紙幣として存在しているため、同じお金を別の支払いに使うことは物理的にできません。コンビニでお菓子を買ったときのお金は自分の手元からなくなりますよね?
しかし、お金をデジタル化したときには簡単にコピーすることができてしまいます。ビットコインはこれを防止することを目的として作られました。

ここでお気づきの方もいるかも知れませんが、Visaや交通系ICカードなどはブロックチェーンなどを使わずともすでに現金のデジタル化に成功しています。これは、サービスを提供するサーバーや管理者を信頼することを前提で成り立っています。サーバーは必ず正しい処理をするか、サーバーのセキュリティは問題ないか、サービスの管理者は絶対に不正をしないか、そういった不確定要素を見ないふりをして私達は電子マネーを使っています。
ビットコインは誰かを信頼することなく動くシステムなのでこの問題も解決することができます。

事前知識

まずは、ビットコインを理解するのに重要な2つの技術を紹介します。

ハッシュ関数

ハッシュ関数とは、文字を入力したときに一定の長さのランダムな16進数を返すような関数です。重要なのは、同じ文字を入力したときには同じ文字を返すという性質です。

1. ビットコイン => b89ae3280372363341c1acef577b58d1e5b7df65a3775c7c8f1788aef9a04b662
2. イーサリアム => 634f66b919cb35371d7b5b0618816b5e606e395c06efa956fa1ff9065db4fa6f
3. ビッタコイン => 1f836071593982ef040a788f399059cded4d56ca5d7037fb3229e4b5684d8f65

出力される文字は、入力が一文字変わるだけで全く違うものになります。

Private Key / Public Key

Private KeyとPublic Keyは安全にデータを送信するために作られた暗号技術です。2つの鍵をセットで使います。
Public Keyを使って暗号化されたデータは、Private Keyを使うことでしか復号できません。また、Public KeyからPrivate Keyを予測することもできません。
詳しくはこちら↓

秘密鍵とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

1. Transaction

誰から誰にいくらビットコインを送ったのかという情報を保存するための仕組みをTransactionといいます。
新しいTransactionを発行する場合は送り先の人のPublic Keyを調べてそれをTransactionに入れる必要があります。さらに自分のPrivate Keyで暗号化した、電子署名と言われるデータを含めることでTransactionの送り主が正しいことを証明できます。


2. タイムスタンプサーバー

タイムスタンプサーバーとは、直前のハッシュ値とデータをハッシュ化して次のデータに含めることでどこか一文字でもデータが改ざんされたときに検知できるシステムです。このデータはこのタイミングで存在していたという証明になるという役割も果たします。


3. Proof of Work (PoW)

Proof of Workは、ブロックチェーンの核となる技術です。
下の図を見てもらうと分かりますが、先程のタイムスタンプサーバーにめちゃくちゃ似てますね。違いはItemがTx(Transaction)になっていることと、Nonceという要素がブロックに含まれていることです。このNonceが重要な役割を果たします。

ブロックチェーン上に新しいブロックを作ってその中にTxを保管しようと思ったとき、Nonce(Number used once)という数字を見つけ出さないといけません。Nonceというのはブロックをハッシュ化したときに、そのハッシュ値の先頭のいくつかに0が並ぶような値です。
例) 0x0000af7238bd0c
この例では先頭に4つの0が並んでいます。ビットコインネットワークでは、いくつ0が並ぶ必要があるのかはネットワークに参加しているノード(参加しているコンピュータのこと)の数と全CPUパワーの合計によって決まります。10分に一回発見されるような難易度に自動的に調整されるのです。
ハッシュ化した後の値は予測することができないので、ひたすら色々な数を入れて計算してみなければいけません。そのため、CPUパワーの高いコンピューターほど高い確率でNonceを発見できます。

もしも、複数のノードが同時に異なるNonceを見つけた場合はどうなるのでしょうか?このときにはチェーンは分岐します。

そして十分に時間がたった後に一番長いチェーンが正しいチェーンとして採用され、採用されなかった方のチェーンは破棄されます。この方法によって悪意のあるTxを含むブロックは採用されなくなります。詳しくは次の章で解説。

4. ネットワーク

ビットコインネットワーク上で新しいTransactionが発行されたときの流れは以下のようになります。

1. 新しい取引は全ノードに送信。
2. 各ノードが新しい取引をブロックに取り入れる。
3. 各ノードがそのブロックへのPoWを算出。
4. PoWを見つけ次第全ノードへ送信。
5. ノードはブロックに含まれるすべてのTransactionが有効で、以前に使われていない場合のみ承認。

すべてのTransactionにはTransaction IDというものが付与されており、過去の取引をそのIDで検索することで以前に使われていないか検証できます。
正しくないブロックは良心的なノードによって破棄されるため、結果的に正しいチェーンのみが残ります。

5. インセンティブ

ブロックの中の最初のTxは新しいコインを発行するための特別なものとなります。そのコインはブロックの作成者(Nonceを見つけた人)のものとなるため、ビットコインマイナーと呼ばれる人たちはブロック生成時の新規コイン発行によって報酬を得ます。
また、Txが発行されるたびに手数料を受け取ることもでき、この2つの報酬によってマイナーがマイニングをする動機づけができます。

6. ディスクスペースを節約する

全ての取引はノードとなるコンピュータのメモリー内に保存されるが、Txが発行されるたびにデータは増え続ける一方であるためメモリー量を減らさなければならない。これは、マークル木と呼ばれる技術によって実現できる。

マークル木では、2つのTxのハッシュ値をまとめてハッシュ化して一つのハッシュ値を作り、更に他のまとめられたハッシュ値とまとめてハッシュ化し、、、と繰り返す事によって最終的に複数のTxを一つのハッシュ値(Root Hash)にまとめます。Txのどれかに改ざんがあるとRoot Hashの値が変わるため、改ざんを検知できます。
ここでもしも上の図のTx0とTx1のデータを参照する必要がなくなった場合、Hash01の値だけを残しておけば改ざんは検知できます。使わなくなったデータを捨ててハッシュ値だけ残しておくことでメモリーを節約することができます。

7. SPV(Simplified Payment Verification)

SPVとは先程の図のブロックヘッダーのみを持っているノードのことを指します。ブロックヘッダーのみを持つことで改ざんの検知ができ、更に必要なメモリーは1000分の1程度まで減ります。
しかし、過去のTxに関する情報が失われてしまうため二重支払いに関する検証を行えません。そこで、それらの検証については全てのTxを保存しているフルノードと呼ばれるノードに依頼します。

-------- よもやま話 -------------------------------
ルノードであることによるインセンティブはありませんが、暗号資産の取引所などは強固なセキュリティと素早い二重支払いなどの不正の検知が必要なためフルノードを建てる必要があります。
ビットコインネットワークは善良なフルノードによって支えられており、データ量が増えるほどフルノードの数は減っていくため、中央集権化が進むことが問題視されています。
---------------------------------------------------

8. 価値の分割

誰かに自分の保有しているコインを送るとき、自分宛に送られた未使用のTxを使用することとなる。
もし自分宛に10コインを送るというTxと15コインを送るというTxの2つのTxある場合自分の保有しているコインは25枚となります。
20コインを送りたいと考えたとき、Txは分割できないため10コインと15コインでは20コインピッタリ送ることはできません。そこで2つのTxを集めて20コインを相手に贈り、5コインを自分に送るという2つのTxを作成することで実質的に20コインを送ることができます。自分宛ての5コインはお釣りと考えても良いかもしれません。

9. プライバシー

プライバシーを保つための方法の一つとして、Public Keyを匿名にすることが挙げられます。
通常Publicキーは誰が発行しているのか公開されるが、匿名で公開することで誰かが誰かにコインを送ったことはわかるが、それが誰なのかは明かされません。
さらに一回の取引ごとに新しいPublic KeyとPrivate Keyのペアを作ることで誰がどのTxを発行しているのか分からなくなります。しかし、Txを発行するときに複数のTxをまとめる場合、それらのPublic Keyは同一人物が発行したものであることが分かってしまうため一定のリスクは避けられません。

10. 改ざんリスク

ここからは少し数学的な話となるため、苦手な人は読み飛ばしてもらって構わないです。
攻撃者がチェーンを乗っ取ることのできる確率について考えていきます。
攻撃者がチェーンを乗っ取るためには良心的なノードが作るブロックの数に攻撃者が作るブロックの数が追いつかなければなりません。

良心的なノードが次のブロックを見つける確率をp、攻撃者が次のブロックを見つける確率をqとして攻撃者がzブロック先のブロックに追いつく確率qzを考えると、

[math]q\tiny z\normalsize =\begin{cases}1 & p \leq q\\\left(\frac{p}{q}\right)^{z} & p > q\end{cases}[/math]

と表される。qzは指数的に小さくなっていくため、ブロックが多く連なると事実上攻撃不可能なところまで確率は下がっていく。

さらに、Txを発行して何ブロック待てば安全と言えるのかを考えてみたい。
自分のTxが発行されてからw個のブロックが追加されるのを待つ。このとき、攻撃者の正確な進捗はわからないが攻撃者の進捗がkである確率P(k)は以下のポアソン分布で求められる。
[math]\lambda=w\frac{p}{k}[/math]
[math]P(k)=\frac{e^{-\lambda}\times\lambda^{k}}{k!}[/math]

攻撃者の追いつく確率Pを求めるには、攻撃者の進捗がkである確率にkの遅れから追いつく確率をかけ合わせれば良いので

[math]P = \sum_{k=0}^{\inf}\frac{e^{-\lambda}\lambda^k}{k!}\times\begin{cases}(\frac{q}{p})^{(z-k)} & k \leq z\\1 & k > z\end{cases}=1-\sum_{k=0}^{z}\frac{e^{-\lambda}\lambda^k}{k!}\left\{1-(\frac{q}{p})^{(z-k)}\right\}[/math]

これにより攻撃者の追いつく確率を求めることができる。

まとめ

ビットコインの論文はなんと9ページで終わっています。9ページで世界を変える発明、すごいですね。でも実際はすでにある技術の組み合わせなので、こういうのを発明と言うんだろうなって思います。さとしすげー。

参考URL

https://bitcoin.dmm.com/glossary/double_payment
eset-info.canon-its.jp
blog.liquid.com
kasobu.com
www.ogis-ri.co.jp
coinpost.jp