GMOアドマーケティングのG.Kです。
ブロックチェーンについてお話したいと思います。
1.ブロックチェーンとはなにか
ブロックチェーンとは、分散型台帳技術、または分散型ネットワークなど
といろいろと定義がありますが、一番カンタンな例で説明していこうと思います。
まず、あなたが女性だと仮定して、あなたの恋人があなたに高額なバッグもしくは
アクセサリーを誕生日にプレゼントすると約束したとします。
喜んじゃってませんか?
しかし、よく考えるとこの状況では、あなたは途端に非常に不利な立場に
置かれてしまいます。
それはなぜでしょうか?
このような非ブロックチェーン的なやり方では、実際にそのプレゼントをするかどうかは
実際100%あなたの恋人の信用に委ねるからです。
このような不利な状況を作らないためにも、私達の生活にはブロックチェーンが欠かせないのです。
では、ブロックチェーン的にはどうすればいいでしょうか?
まずは、あなたの恋人にその約束をメールで送ってもらいましょう。
次に、メールを暗号化しましょう。
暗語化用のアルゴリズムはなんでもよいのですが、この後に作るブロックチェーンでは、
量子コンピューターを視野にいれてSHA256というアルゴリズムを使用します。
ここまで出来たら、あとはあなたの知人、会社の同僚、親戚にその暗号化されたメールを転送します。(※おすすめはしておりません)
そして、やがてその暗号化されたメールは全世界に拡散し、一番最初に暗号を解いた人に
変動価値を持つ手数料を奨励金としてお支払いしましょう。
このわずかな手数料によって、全世界があなたの恋人からの約束を見守るようになり、
このブロックチェーンの技術によって、今まで信用で成り立っている医療や金融の透明性を高め、
さらにはネット広告分野でのアドフラウド問題などを解決することが期待されています。
では、どのようにブロックチェーンを作ればいいのか?
2.ブロックチェーンを作る
まずはJAVAのSDKなど基本的な開発環境が必要で、メモ帳でも良いのですが、IDEもインストールして
おくと楽になります。また、オブジェクトをJSONに変換するために、ライブラリーにはGSONが必要です。
ここまで出来たらブロックチェーンの設計をしていきます。
ブロックチェーンはその名前の通り、単なるブロックで繋がったチェーンなのです。
Hashというのはデジタル署名と呼ばれるもので、暗号化された文字列です。
それぞれのブロックにはそのブロック自身のデジタル署名が含まれているだけでなく、その前の
ブロックのデジタル署名を保存しています。データには何をいれてもよく、取引の詳細や、約束事などをいれることができます。
ここで注意しておきたいのは、現在のブロックのHash、つまりデジタル署名は前のブロックの
デジタル署名とデータに基づいて計算されていることです。
つまり、もしどこかのブロックのデータが変わった場合はHashも変わり、その後にできるすべての
ブロックに影響を与え、ブロックチェーンが無効になってしまいます。
それでは上記の設計を元に、実際にブロックチェーンを実装していきます。
まずは、ブロックのクラスから。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Block { private String data; //データ保存用 public String hash;//デジタル署名を保存 public String previousHash; private long timeStamp; //ブロックができた時間がわかるようにタイムスタンプも格納されています。 //Block コンストラクタ. public Block(String data, String previousHash ) { this.data = data; this.previousHash = previousHash;//1つ前のブロックのHash this.timeStamp = new Date().getTime(); } } |
このようにブロックには、データ、ブロックのHash、 前のブロックのHash、
そしてブロックができた時点の時間としてタイムスタンプが格納されます。
このBlockクラスにはデジタル署名を格納するString型のhashが格納されるのですが、
デジタル署名はどのようにつくればよいのか
上図のように、デジタル署名(hash値)というのは、暗号化された文字列です。
暗号アルゴリズムであればなんでもよいのですが、今回はビットコインと同じ暗号化アルゴリズムSHA256を使用しようと思います。
Javaでは、
import java.security.MessageDigest;
をインポートすることで、暗号化SHA256アルゴリズムを使用することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.security.MessageDigest; public class Sha256Algorithm { //String型のInput値を入力して、ハッシュ値を返す public static String sha256(String input){ try { //メッセージ・ダイジェストは、任意サイズのデータを取得して固定長のハッシュ値を出力する安全な一方向のハッシュ機能です。 MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(input.getBytes("UTF-8")); StringBuffer hexStr = new StringBuffer(); // 16進数としてハッシュ値を持つ for (int i = 0; i < hash.length; i++) { String hex = Integer.toHexStr(0xff & hash[i]); if(hex.length() == 1) hexStr.append('0'); hexStr.append(hex); } return hexStr.toString(); } catch(Exception e) { throw new RuntimeException(e); } } |
上記のようなSHA256のクラスを作り、このクラスの役割は文字列にSHA256アルゴリズムで暗号化することです。
それから最初に作ったBlockクラスで、Hashを計算するメソッドを追加します。
1 2 3 4 |
public String Hash() { String hashValue = Sha256Algorithm.sha256( previousHash + data + Long.toString(timeStamp)); return hashValue; } |
このメソッドでわかるように、現在のブロックのhashValueは前のブロックのHashの値、データ、さらに時間を足したものを暗号化しています。
ブロックチェーンで保存されたデータ自身もHashを計算する一部となっていることで、ブロックで保存されているデータを改ざんすると後のブロックがすべて無効になってしまいます。この性質を利用すれば、例えば今までシェアが不可能だったデータ(健康診断の結果など)を個人情報抜きで全世界にシェアが可能となり(鍵を持つ人だけがアクセス可能)、さらなる発展を促すことができるかもしれません。
次は暗号化メソッドをBlockクラスにあるBlockコンストラクタに入れます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Block { private String data; //データ保存用 public String hash;//デジタル署名を保存 public String previousHash; private long timeStamp; //ブロックができた時間がわかるようにタイムスタンプも格納されています。 //Block コンストラクタ. public Block(String data, String previousHash ) { this.data = data; this.previousHash = previousHash;//1つ前のブロックのHash this.timeStamp = new Date().getTime(); this.hash = hash(); //ここにいれてます } } |
これでブロックは完成です。
あとはブロックをたくさん生成しておけば、勝手にHashで関係性を持つのでチェーンのようになり、
あなただけのブロックチェーンというのが完成です。
1 2 3 4 5 6 7 8 9 10 |
public class Bitcoin2{ public static ArrayList blockchain = new ArrayList(); public static void main(String[] args) { blockchain.add(new Block("(任意のデータ)", "0"));//最初のブロックの前のブロックは存在しないので、0で計算 blockchain.add(new Block("(任意のデータ)",blockchain.get(blockchain.size()-1).hash)); blockchain.add(new Block("(任意のデータ)",blockchain.get(blockchain.size()-1).hash)); //JSON形式に出力 String blockchainToJson = new GsonBuilder().setPrttyPrinting().create().toJson(blockchain); } } |
ちなみに最初のブロックのことを一般的にはGenesis Blockと呼んでいます。
ここまで基本的なブロックチェーンは完成していますが、前述のようにデータの改ざんがあると、
ブロックチェーンが無効になるという性質を持っています。そこで、ブロックチェーンが有効かどうかを判定するメソッドを追加しておく必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public static Boolean isValidBlockchain() { Block currentBlock; Block previousBlock; for(int i=1; i < blockchain.size(); i++) { //今現在のブロック currentBlock = blockchain.get(i); //1つ前のブロック previousBlock = blockchain.get(i-1); //今現在のブロックのHashが計算結果と合わない場合は無効と返す if(!currentBlock.hash.equals(currentBlock.Hash()) ){ return false; } //1つ前のブロックのHashが計算結果と合わない場合は無効と返す if(!previousBlock.hash.equals(currentBlock.previousHash) ) { return false; } } return true; } |
上記のメソッドをBitcoin2クラスに追加します。
これによって、いかなるデータの改ざんでもこのメソッドはfalseを返し、無効なブロックチェーンだと判定します。
ビットコインのブロックチェーンネットワークでは、一番長い(ブロック数の多い)有効なブロックチェーンが本物のビットコインのブロックチェーンとして判断されています。
ちなみに、過去のブロックの改ざんを阻止しているのはProof of Workと呼ばれる仕組みです。
いわゆるマイニングです。
ビットコインのマイニングでは、まず、データをまとめたブロックを生成し、次にブロックチェーンへの追加権利をかけて、計算問題を解いていき、一番早く答えを出せたマイナーは、答えを他のマイナーに報告し、ほかのネットワーク参加者が、正否を判断、正解ならば、そのマイナーが生成したブロックをブロックチェーンに追加し、報酬が得られる仕組みとなっています。
今回計算問題として出すのは、ユーザーに異なる値を入れてもらい、hash値が指定の数の0から始まるまで試し続けます。
まず、Block クラスのHash() にint answerを追加していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class Block { public String hash; public String previousHash; private String data; private long timeStamp; private int answer; //Block コンストラクタ. public Block(String data,String previousHash ) { this.data = data; this.previousHash = previousHash; this.timeStamp = new Date().getTime(); this.hash = Hash(); } public String Hash() { //answer をhashに含みます。 //マイナーさんは正しいanswerを計算する必要があります。 String hash = Sha256Algorithm.sha256( previousHash + data + Long.toString(timeStamp) + Integer.toString(answer); return hash; } } |
このように、answerはhash値を出すための一つの変数となっています。
さらに、このようなマイニングに必要なメソッドもBlockクラスに追加しておく必要があります。
1 2 3 4 5 6 7 8 |
public void mineBlock(int difficulty) { String targetedHash = new String(new char[difficulty]).replace('\0', '0'); while(!hash.substring( 0, difficulty).equals(targetedHash)) { answer ++; hash = Hash(); } System.out.println("マイニング成功!ブロックHash : " + hash); } |
このように、difficultyはマイニングの難易度となっています。
例えば、difficulty = 1 ならば、hash = 0J19JK812kK… のように0が1個から始まっていれば、マイニング成功です。
しかし、difficulty = 5 にすると、hash = 00000AH23KJ…のように0が5つ連続で始まらなければなりません。
マイニングマシーンはこのanswerを1つずつ足して答えを見つけなくてはなりません。
(そういうわけで、高度な計算に得意なCPUよりも単純作業同時に多くできるGPUやASICのほうがマイニングに優れています)
ちなみに今2018年12月26日ですが、実際のビットコインのdifficulty は5,106,422,924,659となっています。
上記と同じ計算問題が出されると仮定しますと、マイニングマシーンは5,106,422,924,659個の0が連続で出てくるまで計算を続けなくてはなりません。
(わかりやすく説明するために今回はこのような計算問題を選びましたが、実際にビットコインで使われる計算問題はやや異っており、256bitのhashでそんなに0が多く出てくることもないかと思います。)
このdifficultyはビットコイン価格で調整され、価格が下がればdifficultyも下がるようになっていて、計算時間が短くなりより電気代が安くなるような仕組みとなっています。
マイニングマシーンの性能は採掘速度(ハッシュレート)で評価されています。hash/s(1秒間に1ハッシュの計算)という単位が使われています。例えばハッシュレート10T(テラ)H/sに達したということは、1 秒あたり 10 兆回ハッシュの計算ができるということになります。
最後にBitcoin2クラスにブロックがマイニングされているかどうかを確認するメソッドも追加していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public static Boolean isValidBlockchain() { Block currentBlock; Block previousBlock; String targetHash = new String(new char[difficulty]).replace('\0', '0'); for(int i=1; i < blockchain.size(); i++) { //今現在のブロック currentBlock = blockchain.get(i); //1つ前のブロック previousBlock = blockchain.get(i-1); //今現在のブロックのHashが計算結果と合わない場合は無効と返す if(!currentBlock.hash.equals(currentBlock.Hash()) ){ return false; } //1つ前のブロックのHashが計算結果と合わない場合は無効と返す if(!previousBlock.hash.equals(currentBlock.previousHash) ) { return false; } //マイニングされたかどうかをチェック if(!currentBlock.hash.substring( 0, difficulty).equals(targetHash)) { return false; } return true; } |
次回はイーサリアムのスマートコンタクトについて書こうと思います。