はじめに
私は最近Rustを勉強し始めたのですがあまりにも難しすぎて挫折しかけていました。おそらく、何の目標もなく勉強していたからでしょう。
そこで今回は、Rust学習に挫折しかけている筆者がRustの基本的な部分の勉強を飛ばし、いきなりではありますが、一つの目標として「仮想通貨」を実装していきたいと思います。
本記事では、実装にあたってまずは仮想通貨の仕組みについて説明していきたいと思います。
続編では【実装編】を予定しています。実装編ではRustの勉強を兼ねつつ実装を進めていきたいと思います。
上述の通り筆者は初心者であるため、未熟な点や誤りが多々あると思いますが、勉強・実装しつつまとめていますのでご了承いだけますと幸いです。
仮想通貨とは
ブロックチェーンや公開鍵暗号方式、P2P、ハッシュのような技術を用いた仮想的な通貨のことです。
コンピューター上に存在し、ネットワークで取引が行われるます。暗号理論を基盤としているため、暗号通貨とも呼ばれています。
有名なものとしては、ビットコインがあります。
厳密な定義は日本では資金決済法によって定められていますが、今回は省略させていただきます。
似たものとして、日本円やドルなどの通貨を基盤にした電子マネーというものがありますが、これは「通貨建資産」といい、仮想通貨には含まれません。
仮想通貨を実現する技術
仮想通貨は、以下に示すような技術を用いて実装されています。
- ブロックチェーン
仮想通貨の取引データをブロックと呼ばれるものにまとめ、チェーン状にしたデータ構造のこと。 - ハッシュ
入力した値を、あるアルゴリズムに基づいて計算し生成された不可逆な固有の値のこと。 - プルーフオブワーク
ブロックチェーンの改ざんを防ぐために、ブロックの生成に意図的に時間をかける仕組みのこと。 - 電子署名
暗号技術の一種で、デジタルデータの改ざんやデータ作成者のなりすましを防ぐための仕組みのこと。 - 公開鍵暗号方式
暗号技術の一種で、暗号化と復号にそれぞれ異なる鍵(それぞれ、公開鍵と秘密鍵)を使用する。電子署名を実現するための技術でもある。 - ピアツーピア
ネットワーク内の参加者が対等に通信しあう方式のこと。反対に、中心的な装置を持ち、通信の際にはその装置を経由する通信方式としてクライアント・サーバー方式がある。
以降では、これらについて説明させていただきたいと思います。
ブロックチェーン
そもそもブロックチェーンとはなんでしょうか?
仮想通貨の中心的な技術で、取引データを記録していくもの(台帳)のことです。そして、改ざんを防ぐ機能も備わっています。
ブロック自体は、仮想通貨そのものではありません。仮想通貨自体には実体はありませんが、送受信したという事実を記録することで、あたかも本当に送受信しているように見せかけているのです。
▼ブロックチェーン
先頭のブロックはジェネシスブロックとも呼ばれます。
トランザクション
取引データは「トランザクション」と呼ばれます。
ブロックチェーンではこのトランザクションをブロックに格納します。
上述の通り、ブロックにはトランザクションが格納されますが、このトランザクションとはどのようなものでしょうか?
仮想通貨では、送金する時に送金元は自分の持っているコイン(を使用する権利)を使用し、送金先にコイン(を使用する権利)を発行します。
このコインを使用する権利は、UTXO(Unspent Transaction Outputs) を呼ばれます。言い換えると、まだ使っていないコインの受け取った時のトランザクションのことです。そのため、これが「もらったコインのうち、まだ使っていないもの」だといえます。
仮想通貨には硬貨や紙幣のような実体がないため、コインを使用する権利を受け渡しすることで取引が行われます。
しかし、仮想通貨はこのような単純な仕組みだけではありません。
もう少し、具体的に説明します。
例えば、アリスが100コイン持っている時に、ボブに30コインだけ送金したいという場合があるとします。
ここで、アリスは現在所有しているコインをトランザクション0001番の取引(TX0001)によって得たコインだとしましょう。
まず、アリスは100コインを得たTX0001(UXTO)をもとに、ボブへのトランザクション(TX0002)を作成します。TX0002にはボブに30コイン送金するという情報と、アリス自身に70コイン送金するという情報を書き込みます。
つまり、アリスは全額支払った上で、「お釣り」を受け取るようなイメージです。
混乱しそうになりますが、アリスはTX0001というまだ使用していないコインを受け取った時のトランザクション、すなわちUXTOをもとにして新しくTX0002を作成するため、TX0001で受け取ったコインを全額送金することになります。しかし、これだけではアリスが余分に送金してしまっているため、払い過ぎた分だけお釣りとして取り戻すということです。
では、実際にトランザクションに記録されている情報はどうなっているのでしょうか?
トランザクションは、大きく分けて「インプット」と「アウトプット」の2つから構成されています。
▼トランザクションの構造
インプットには、送金のもととなるトランザクションの番号(TX0001)が記録されます。送金額が高額な場合など複数のUXTOを使用するときには、その個数も記録されます。
アウトプットには、ビットコインの送金先や送金額に関する情報が記録されます。上の例でいえば、ボブ宛に30コイン、アリス宛に70コイン送金するという2個の情報が記録されます。送金先がもっと多い場合もあります。
実際のデータとしては、宛先は口座番号に相当するアドレスで指定されます。(後述しますが、原理的には送金先の人が持っている秘密鍵に対応する公開鍵が宛先に相当します)
▼TX0002に記録される情報
※公開鍵や電子署名については後ほど説明します。
より正確には、マイニングをした人(マイナー)に支払われる、手数料など様々な情報が記録されますがここでは省略します。
マイニングについては、後ほど説明します。
ブロックの改ざん防止
仮想通貨の取引は実体を伴わないデータ上のやり取りでしかないため、ブロックの情報を不正に書き換えることができるかもしれません。
例えば、コインを使用したトランザクションを削除して同じコインを複数回使用する「二重支払い」ができたら大金持ちになれることでしょう。
しかし、残念ながらそのようなことはできないように対策がされています。
これが、ハッシュ化と呼ばれる技術によるものです。
ハッシュとは、入力した値を、あるアルゴリズムに基づいて計算し生成された不可逆な固有の値のことだと説明しました。ハッシュ化とは、入力した値から不可逆な固有の値を計算することを言います。
詳細なハッシュアルゴリズムに関する説明は省略しますが、有名なものではビットコインにも使用されているSHA-256やRIPEMD-160があげられます。
例えば、"Hello"をいう文字列を入力としてSHA-256にしたがって計算すると"185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969"いう値が出力されます。
ハッシュ化には以下のような特徴があります。
- 同じデータを同じアルゴリズムでハッシュ化した場合は、常に同じ値が出力される
- ハッシュ化された値から元の値を計算することは非常に難しい("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969"が"Hello"をハッシュ化した値であると逆算して突き止めることは非常に難しい)
- 入力を少し変えただけでも、出力される値は大きく変化する(例えば、"Hello1"をハッシュ化すると"948edbe7ede5aa7423476ae29dcd7d61e7711a071aea0d83698377effa896525"となる)
- 同じハッシュ値になる文字列を見つけることは非常に難しい
ブロックチェーンでは、前のブロックをハッシュ化した値を次のブロックに記録したり、マークルルートというブロック内のトランザクションをハッシュ化した値を持つことで、改ざんを防止しています。
まずは、マークルルートについて説明したいと思いますがその前に、マークルツリーについて説明します。
マークルツリーとは、ブロック内に含まれる複数のトランザクションのうち2つずつペアにしてハッシュ化して得られた値をもと、さらにペアごとにハッシュ化していくことで作られるツリー構造のことです。
その処理をした結果得られる、1番上の値がマークルルートになります。
トランザクションの正当性を検証するだけなら、マークルツリーを作る必要はありませんが、複数のトランザクションをまとめたハッシュ値(マークルルート)を利用することで、効率的に検証を行うことができるようになります。
次に、前のブロックのハッシュ値を後続のブロックが持つという仕組みについて説明します。
なぜ、このような仕組みで改ざんを防止できるのでしょうか?
それは、あるブロックを変更(改ざん)すると、後続のブロックをすべて作り直す必要があるからです。1つでも辻褄が合わないハッシュ値を持つブロックは不正なチェーンであると判断することができます。また、マークルルートとトランザクションの内容で
しかし、近年のコンピュータではハッシュ値の計算自体はかなり高速で行うことができるため、後続のブロックをすべて作り直すことができてしまうかもしれません。このままでは、まだ改ざんすることができてしまいます。
そのため、改ざんを難しくするためにはブロック作成にあえて時間がかかるようにする必要があります。
この仕組みのことをプルーフオブワークといいます。"Proof of Work"を略して、PoWと表記することもあります。
"Proof of Work"とは「仕事をした証明」ということを意味します。
プルーフオブワークは、ある人がブロックを作り、他の人はその処理が正しいものか確認するという手順で行われます。
そのため、処理には時間がかかるが確認は短時間で済むという性質を持つ必要があります。
このプルーフオブワークに適した処理とは何でしょうか?
先ほど、「ハッシュ化された値から元の値を計算することは非常に難しい」と述べましたが、これを利用した処理を行います。
例えば、「ハッシュ値がある値より小さい値になる値を見つける」という処理はどうでしょうか?
ハッシュ値から元の値を計算することは難しいため、この処理は何度も繰り返しハッシュ値を計算することでしか見つけることができません。
具体的には、
目標の値を仮に「ハッシュ化した値が1500以下の値」と設定しましょう。
この値を「ハッシュ値が1300となるのは"abcd"だ」というように、一発で求めることは非常に困難です。
「"abce"のハッシュ値は1650、"abcf"のハッシュ値は1730...」のように1つずつ値を計算した結果「"axyz"は1250だ」というように答えにたどり着くことができます。
正しいか確認するコンピュータは"axyz"を1度ハッシュ化し、1250が本当に1500以下であるか確認するだけで済みます。
このような処理を挟むことによって、ブロック作りにあえて時間をかけることで改ざんを防止することができます。
正確には、改ざんをすること自体は可能ですが、改ざんをした後に後続のブロックが持つハッシュ値と辻褄が合わなくなることで改ざんを検知することができます。後続のブロックをすべて書き換えるためには膨大な時間がかかる処理を行う必要があり、その処理をしている間に新しいブロックが追加されるとさらに処理が増えるため現実的には改ざんできなくなります。
51%攻撃という手法を使えば、この仕組みを逆手にとって改ざんをすることも可能ですが、詳細は後述します。
ブロックの中を書き換えてブロック自体のハッシュ値を目標のハッシュ値にすることがプルーフオブワークです。しかし、ブロックの中の取引に関する情報(トランザクション)などを勝手に書き換えてはいけません。これをやってしまうとそもそも取引が成立しませんね。
そこで、ブロックにノンスという値を組み込みます。
このノンスは自由に書き換えることができる領域とし、ブロックを作成する人はこれを書き換えることでブロックをハッシュ化した値が目標の値となるように何度も書き換え・ハッシュ化を繰り返します。
その目標となるノンスのことをゴールデンノンスといいます。
ゴールデンノンスはハッシュ値を目標値以下にする値のことを指すため、複数個存在します。
この目標の値が大きいければ、ゴールデンノンスは容易に見つかりますが、小さい値であれば何度も計算をし直す必要があります。つまり、この目標となる値によって難易度が変化します。
先ほどの例であれば、目標となる値を1500としていましたが、これを1000にすると難しくなりますが、2000にすると簡単になるということです。
仮想通貨の場合は、ある程度時間をかける必要がありますが長すぎるといつまでもブロックが生成されなくなってしまうという問題が発生するので難易度の調整も大切です。
ちなみに、ビットコインでは、約10分程度の時間がかかるように調整されています。
ここまでノンスについて説明してきましたが、実はこのゴールデンノンスを見つけるプロセスこそがマイニングと呼ばれているものです。
チェーンにブロックを繋ぐ処理の前にわざと時間がかかる処理「マイニング」を行わせることで、チェーンを改ざんできないようにしています。マイニングをしなければチェーンにブロックが繋がることはないため、マイニングをする人(マイナー)は欠かせない存在です。
マイニングをすると報酬としてその仮想通貨が支給されるため、これに参加する人が現れるのです。
要するに、このマイニングを行いブロックの生成に時間をかける仕組みがなければすぐにブロックを改ざんすることができてしまうため、仮想通貨の維持には欠かせないものなのです。
ブロックチェーンを用いる仮想通貨では、通貨を発行する機関は存在しません。では、どこから通貨が現れるのかと思われる方もいらっしゃるかもしれませんが、このマイニングで支払われる報酬によって、次第に市場の供給量が増えていくという仕組みになっています。
このマイニングによって支払われる報酬も当然、トランザクションに書き込みます。これによって通貨が生み出されるため、このトランザクションはジェネレーショントランザクションまたはコインベーストランザクションと呼ばれます。
ちなみに、通貨が増えてしまうと価値が少なくなるため、インフレが発生してしまいます。そのため、ビットコインの場合はこのマイニングによって支払われる報酬には限度が2100万BTCに設定されています。これでは、いずれマイニングする人がいなくなってしまうのかという話になりますが、その心配はいりません。なぜなら、マイニング報酬以外にも送金者が支払う「トランザクション手数料」というものがあるため、完全に0になるといわけではないからです。
公開鍵暗号と電子署名
先ほど、トランザクションの話の中で公開鍵や電子署名というワードを使いました。
電子署名とは、コインを使う人が正当な権利を持っているかを確認するための仕組みのことです。「署名」という名の通り、紙とペンで行う署名に似たものをデジタル上で実現することができます。
と言っても、別にタッチパネルで実際にサインをするというわけではありません。
ここからは、この電子署名の仕組みについて説明していきたいと思います。
まず、電子署名は、公開鍵暗号方式という仕組みを使用します。
公開鍵暗号では、公開鍵と秘密鍵という2種類の鍵を使用します。
- 公開鍵
通信相手はもちろんのこと誰にもでも公開して良い鍵です。 - 秘密鍵
本人のみ知っており、通信相手にすら教えてはいけない秘密の鍵です。
次に、電子署名は、署名と検証という2つのプロセスで成り立ちます。
- 署名
秘密鍵を用いて、署名したいデータ(のハッシュ値)から電子署名を作成すること - 検証
秘密鍵とペアになっている公開鍵を用いて、電子署名が正しいかどうかを確認すること
検証では、もし電子署名が正しければ公開鍵を用いて電子署名を変換すると元のデータのハッシュ値が出現することになります。検証する人は、「送られてきたデータをハッシュ化した値」と「電子署名を公開鍵を用いて変換した値」が一致するかを確かめることで、本人確認をすることができます。
たったこれだけなのかと思いますが、公開鍵をペアになっている秘密鍵は本人しか知らない情報であるため、公開鍵で正しく変換できたということは正しい秘密鍵で変換したと言えるのです。もし、改ざんされていたら検証した結果が一致しないので改ざんに気づくことができます。
このあたりのことは筆者もまだ勉強中なので非常に曖昧な説明になってしまいました。
Rustで実装する前には、しっかり理解したいと思いますが、それはまた今度ということにさせていただきます。(ハッシュ化についても、いつかまとめたいと思っています。)
実際に、仮想通貨において電子署名はコイン使用時に行われます。
コインを誰かに支払うには、まずコインに新しい所有者の公開鍵を記載した上で、古い所有者が秘密鍵で署名を行います。この電子署名は、ブロック内のトランザクションに記録しておきます。
送信者が上記のようなトランザクションを作成することで送金をすることができます。(正確には、このトランザクションが書き込まれたブロックをチェーンに繋ぐことで送金が完了します。また、このトランザクションはマイナーに対する報酬を考慮していません。)
コインには「所有者の公開鍵」と「所有者の秘密鍵で作成された電子署名」が記録されているため、この2つを使えば本当にその人が所有者なのかを確かめることができるというわけです。
コインの所有者は、コインに記録された公開鍵とペアになる秘密鍵を持っていることで所有権を主張することができるようになります。(そのコインを使用する時はその秘密鍵を使って、新たに電子署名を作成するため。)
ちなみに、公開鍵暗号方式としてはRSA暗号が有名ですがビットコインでは楕円曲線暗号をもとにした楕円曲線DSAという方式を採用しています。
ピアツーピア
ピアツーピアは中心となるサーバーを経由せずにネットワーク内の参加者が対等に通信しあう方式のことです。ピアツーピアは"Peer to Peer"を省略して「P2P」と表記されることもあります。
仮想通貨では参加者が全員チェーンのデータを持っており、新しく入ってきた人はすでにネットワーク内に参加しているいずれかの人と通信を行いチェーンのコピーを受け取ることで仮想通貨を利用し始めることができます。
このように複数の人がチェーンのデータを持っているため、誰かがネットワークを抜けたとしてもチェーン自体は維持し続けることができます。
ブロックチェーンの管理
仮想通貨ではピアツーピアでブロックチェーンを管理していると説明しましたが、チェーンが複数になると各マイナーがマイニングに成功したタイミングによってチェーンの長さが同じネットワーク内でも異なってしまう可能性があります。
ピアツーピアのネットワーク内ではお互いが対等な立場にあるため、管理者がどちらのチェーンが正しいということを決めることはできません。
そのため、仮想通貨では「最も計算に手間がかかるチェーンを採用する」というルールになっています。そのため、新しいチェーンがネットワーク内で共有されるたびに自分の所有するチェーンが新しいものより短い場合は破棄することになります。
せっかくマイニングして報酬を受け取ったとしても、タイミングが遅かった場合は他のチェーンが長くなるため、送金や報酬が0になってしまう可能性があります。仮想通貨の種類や取引所にもよりますが、その後にブロックが数個繋がった場合のみ、取引が承認されるという仕組みがあります。
「それでは、いつまで経っても100%取引が確定することはないじゃないか!」と思うかもしれませんが、実際には同じ速度で別のブロックが伸び続けない限りいずれかのチェーンが最長になるので、短い方が破棄されます。長期間、同じ速さで別々のチェーンが伸び続けることは考えにくいため、ある程度時間が経てば確定といえるのです。
実は、この最も計算に手間がかかるチェーンを採用するというルールとプルーフオブワークの仕組みを組み合わせると、51%攻撃という不正行為が可能になってしまいます。
不正行為の例として二重支払い(同じコインを2度使用すること)をすることを考えてみましょう。
- 攻撃者は仲間に送金を行い、現金化する
- 1のトランザクションが通常通り、チェーンに記録される
- 攻撃者が持つ正規のチェーンの中から1のトランザクションを削除して改ざんしたチェーンを作成する
- 改ざんしたチェーンは通常、正規のチェーンよりも短くなるが攻撃者は手元で保管し続ける
- 攻撃者は他のマイナーよりも早くマイニングを行うことで、改ざんしたチェーンを正規のチェーンよりも長くする
- 改ざんしたチェーンをネットワークに伝播させ、正規のチェーンを破棄させる
上記の手順を行えば、送金した記録を消しているためもう一度送金することができてしまいます。
このような攻撃を実現するためには攻撃者は他のマイナーより速くブロックを作成する必要があります。そのためには、攻撃者の計算性能が攻撃者以外のマイナーの計算性能を上回る(51%以上になる)必要があります。
この「51%以上の計算性能が必要」ということから「51%攻撃」と呼ばれています。
ですが、通常はビットコインのように多くのマイナーがいる仮想通貨では他のマイナーの合計計算性能を上回るほどの計算性能を用意することはコストが膨大になり、非常に困難なため実行されるリスクは少ないとされています。
ビザンチン将軍問題
ビザンチン将軍問題とは、中世ヨーロッパのビザンチン帝国を包囲するオスマン帝国の複数人の将軍が攻撃計画についてどのように合意を形成するかを扱った問題に由来するコンピュータ科学に関する問題のことです。
今、将軍たちは攻撃か撤退かを選択しなければいけませんが、全軍一致で行動しなければ計画は失敗してしまうため、複数人の将軍は全員で合意形成をしなければなりません。しかし、将軍の中にも反逆者がいるかもしれないという状況です。
この問題は、ブロックチェーンにおいて どのチェーンが正しいかを合意形成する仕組みに関連しています 。
ブロックチェーンの参加者の中には不正なチェーンを伝播させようとする人もいるかもしれません。そのような場合に、ネットワーク全体でどのように正しいチェーンを採用するかという合意形成をする必要があります。
ブロックチェーンでは、この合意形成をするためにプルーフオブワークを行い、最も計算に手間がかかっているチェーンを採用するというルールによって正当性を維持しています。
まとめ
仮想通貨はプルーフオブワークや公開鍵暗号、電子署名など様々な技術を組み合わせて実現されています。「この場合はどうするんだろう?」、「こうやったら不正できるのでは?」といったような疑問が出るたびに、それを解決する方法が存在しており、非常に優れた仕組みだと圧倒されました。
次回以降の【実装編】では今回、解説した仮想通貨の理論を実際にRustで実装していきたいと考えています。
Rust学習を兼ねていますが、次回以降で文法などを網羅的に解説することは難しいため、基本文法は押さえつつ楽しくRust学習を進めていければ良いかなと考えております。また、冒頭でも説明しましたが、筆者は仮想通貨やRustに関して勉強中の初心者であり、本記事には誤りが含まれている可能性がありますのでこの点に関してもご了承ください。
ここまで、読んでいただきありがとうございました。