JavaScript
アルゴリズム

Provably Fairとその悪い使い方

Provably Fair

ここ数年でビットコイン等を賭けたりする、オンラインカジノで利用されているアルゴリズムのプロバブリーフェア1 (立証可能なフェア)について説明します。

またその悪い使い方についても解説します。

1. プロバブリーフェアとは

オンラインカジノなどでは、やろうと思えばゲームホスト側が意図的に勝てるようにすることができます。

そこでフェアにする為のアルゴリズムがプロバブリーフェアです。

先にサーバー側がロール(振り目、乱数、シード値)をハッシュ化しプレイヤーに伝えるこどで、後で不正をすることが出来ないということを保証します。

MegaDice2で利用されている一例を説明します。

chart.png

① ゲームの開始

ゲームを開始します。

② サーバーのロール

サーバー側が始めに振り目を決めます。

また、Saltというハッシュ化する際に特定を難しくする為のランダムな文字列も決めます。

以上の2つを組み合わせ、SHA-2等の暗号学的ハッシュ関数でハッシュ化します。

このハッシュをクライアントに渡し、次に進みます。

サーバー.js
const Random = Math.random() * 100000        //→ 80719.44569750382
const Salt = RanmdomString()                 // RanmdomStringはランダムな文字列作る架空の関数
const Hashed = SHA256(Random + '_' + Salt)   // SHA256は文字列をハッシュ化する架空の関数
//→ 98fd4c46069842474adef848863e8eaca4af1cce2dede172af2ea5e9a0f20969

この時点ではホスト側は必ず振り目とソルトを隠します。

③ クライアントのロール

クライアントはハッシュを受け取り、これはフェアなゲームだと確認した上で振り目を決めます。

プレイヤー側は値をそのままサーバーに送信します。

クライアント.js
const ServerRollHash = '98fd4c46069842474adef848863e8eaca4af1cce2dede172af2ea5e9a0f20969'
const ClientRandom = Math.random() * 100000
//→ 53127.75250042807

④⑤ ゲームの最終乱数値と結果

サーバー側はクライアントの決めたランダム値とサーバーのランダム値を合わせます。

サーバー.js
const MaxNumber = 65536  // ゲームのさいころの最大値
const RecivedClientRandom = 53127.75250042807
const Result = Math.floor( (RecivedClientRandom + Random) % (MaxNumber + 1) )
//→ 2773

これでゲームの(大きな)さいころの振り目が決まります。

⑥ 振り目の検証

最後にクライアントはサーバーが使っていた乱数とソルトを知ることができます。

この情報を元に検証し、このゲームがフェアだったことを確認することができます。

クライアント.js
const MaxNumber = 65536  // ゲームのさいころの最大値
const RecivedServerRandom = 80719.44569750382
const RecivedServerSalt = 'f89034eh89ghdfhgu904u8ujgri0sjgkl23j'
// ハッシュの検証
console.assert( ServerRollHash === SHA256(RecivedServerRandom + '_' + RecivedServerSalt), 'Fraud!' )
// 結果の乱数の検証
const Result = 2773
console.assert( Result === Math.floor( (ClientRandom + RecivedServerRandom) % (MaxNumber + 1), 'Fraud!' )

ハッシュ関数で作られた文字列は改ざん不可で、それから元の値を知ることはできないとされています。

その為これはフェアだったと確認することができました。

2. フェアではない見せかけのプロバブリーフェア

一見するとフェアですが、少し違う方法をとっているとフェアでない場合があります。

以下のフローがフェアではない一例です。

scam.png

しっかりハッシュ化されたサーバーの振り目を伝えていてフェアに見えます。

しかしながら、クライアントが振ったランダムな値が利用されていません。

つまりホスト側は最初から結果を知ることが出来ます。悪用例を挙げてみます。

悪用例

あるカジノではコインフリップというゲームがあります。

プレイヤー対プレイヤー(PvP)方式で、賭けた額の割合が勝率になります。

  • プレイヤー1とプレイヤー2がいます

  • ここでは同じ額賭けたことにします(50:50)

  • どちらにも予めサーバーの値のハッシュが伝えられます (Probably Fair)

  • さいころは整数で1..100の範囲です

  • サーバーが決めた値の範囲に入っている人の勝ちになります

以上の設定を図にします。

scamex.png

この状況で、さいころの数値が30だった場合はプレイヤー1の勝ち、70だった場合はプレイヤー2の勝ちになります。

このゲーム上で、サーバーが既に振り目を知っているとサクラ(bot)を入れて意図的に運営が勝ちをかっさらえるようになります。

実際に、運営がBOTをプレイヤーに見せかけ儲けを得るというのもありました。3

3. 注釈等

ギャンブルはやめとこうね

悪用例の方法ですが、PvP方式でない場合は問題がないかもしれません。