【CryptZombies】レッスン4チャプター4:乱数
Solidityにおいて、安全な乱数の生成は不可能です。
理由は次の通り。
keccak256経由での乱数生成
Solidityではkeccak256ハッシュ関数を使って乱数を生成します。
// 1から100までの乱数を生成せよ:
uint randNonce = 0;
uint random = uint(keccak256(now, msg.sender, randNonce)) % 100;
randNonce++;
uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100;
このコードが行うのは、nowのタイムスタンプとmsg.sender、増加する値nonce(一度飲み使用される数字なので同じ入力パラメータ値を持つハッシュ関数が二度実行されることはない)の受取りです。
keccakでこれらの入力値をランダムなハッシュ値に変換、そしてそのハッシュ値をuint型に変換したら、その末尾2桁のみ残すように%100をします。こうして0から99の間の、完全にランダムな数値を生成します。
この方法は、不誠実なノードの攻撃に対して脆弱
Proof of Work
イーサリアムでは、コントラクトの関数を呼び出す際、ネットワーク上の一つまたは複数のノードにトランザクションとして送信し、ネットワーク上のノードはトランザクションの束を集め、Proof of Work(PoW、仕事の証明)として計算集約的数学の問題を一番速く解こうとします。そして彼らのProof of Workも併せたトランザクションのグループをブロックとしてネットワークの残りのノードに発行します。
一度あるノードがPoWを解いてしまうと、他のノードはそのPoWを解くのをやめ、トランザクションリストが有効であることを確認してブロックを承認し、さらに次のブロックを解くことに取り掛かります。
乱数関数のセキュリティホール
コイン・トスのコントラクトがあると仮定します。表ならお金が2倍、裏ならお金を失うというルールです。表裏を決定するのに、乱数関数を使うとします。(random >= 50なら表、random < 50なら裏)
Aさんがノードを立てているとして、Aさんが自分のノードだけに向けてトランザクションを発行します。すると、コイン・トスの関数の勝ち負けを見て、次のブロックにそのトランザクションが含まれないように選択することができてしまいます。コイン・トスに勝って次のブロックを解くまでこれを無期限で行い続け、利益を出すことが可能です。
ただし、ブロックを解いて利益があるようにするためには、膨大な時間とリソースが必要です。なので、その報酬が十分に高くなければ、不正を働くメリットはありません。
したがって、使用する乱数関数が大金を危険にさらさない限りは、乱数関数を使用することのトレード・オフを受け入れていくことも必要です。
テストの実行
①コントラクトに、randNonceというuintを与え、0に同等となるよう設定せよ。
②randMod(random-modulud)という関数を作成せよ。これは_modulusという名のuintを受け取るinternal関数であり、uintを返す(returns)。
③この関数はまずrandNonceを増やさなくてはならない。(randNoce++という構文を使うのだ)
④最後に、now、msg.senderそしてrandNonceのkeccak256ハッシュ値の型変換をuintに計算し、その値を% _modulusしてreturnせよ。これはコード1行で行うこと。
まず赤線から見ていきます。
次に、青線を見ていきます。
上で変換したkeccak256ハッシュ値をuint型に変換します。
それから、オレンジ線を見ていきます。
最後に緑線を見ていきます。
お疲れさまでした!
<参考>
CryptoZombies - イーサリアム上でゲームを開発する方法を学習。Powered by Loom Network