Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

コミットメントスキーム(=ビットコミットメント)

コミットメントスキームの概念を理解するために、まず、コイン投げプロトコルを考えます。

Alice,Bobの2人が同じ場所に居合わせ、Aliceがコインを投げ、Bobが表が出るか裏が出るかを当て、勝敗を決めるゲームを考えます。
このゲームの手順のことをプロトコルと言います。

コイン投げプロトコル

1) Aliceがコインを投げて手の中のコインの表,裏を確定させる。
表,裏どちらになっているかはAliceは知っているが、Bobには分からないものとする。
2) Bobが表,裏どちらかを推測し、宣言してAliceに伝える。
3) Aliceが手を開き、表,裏をBobに見せる。
Aliceの手の中の値とBobが宣言した値を比較し、同じならBobが勝利、異なればAliceが勝利となる。

1)でコインの表裏が確定した手のことをコミットメントといいます。
1),2)の手順のことをコミットメントフェーズと呼びます。
3)の手順のことをオープンフェーズと呼びます。

秘匿性 ( hiding property )

Bob が1)の時点で、表裏の情報の分からなさがどの程度かを秘匿性の度合いと言います。
例えば、BobがAliceの手のレントゲン写真を取れば、手の中の状態が分かりますから、その程度の秘匿性ということです。

束縛性 ( binding property )

Alice が3) で手を開く時に、ズルをして、1)で確定したコインの表,裏を異なるものとして
公開することがどの程度できないかの度合いを束縛性と言います。
Alice が実は高度なテクニックを持つマジシャンであれば、2) でBobがAliceに伝えたのと逆側をオープンすることができます。

離散対数問題(DLP)を用いてみる

さすがに、人の手を使うのは、秘匿性も束縛性も低すぎますから、精度を上げるために、離散対数問題という数学を用います。

ここ Commitment scheme - Wikipedia

のリンクの「A perfectly binding scheme based on the discrete log problem and beyond」 に書かれた方法を使ってみます。

離散対数問題では、解はただ一つしかありませんから束縛性は完全になります。
また、離散対数問題は計算量的に解くことが困難とされていますから、秘匿性は計算量的になります。

秘匿性が計算量的であれば、暗号として使うには強度として十分と言えます。

離散対数を用いた時のプロトコル

p, q を大きな素数とし、q|(p-1)であるとする。
gを Z_p^*の部分群の生成元とする。なおこの部分群の位数はqとする。
aを Z_qからランダムに選び秘密の値とする。
 h = {q}^{a} \mod pとする。
(p, q, g, h)を公開し、(a) を秘密とする。

メッセージ  m \in Z_q をコミットするため、送信者はランダムに r \in Z_qを選び、
コミットメント c = {g}^{m} {h}^{r} \mod pを受信者に送ります。
オープンフェーズとして、送信者はm,rを明らかにし、受信者は c = {g}^{m} {h}^{r} \mod pであることを確かめます。

何に使うのか?

仮想通貨のトランザクションの匿名化に用いられているようです。

Moneroで使われているので、詳しくはこの辺りを参照してください。

Monero日本語解説シリーズ\\ {\Large Monero Japanese Article Series - Overleaf

Pedersen Commitment | Moneropedia | Monero - secure, private, untraceable

個人的おすすめアルトコイン(8) - "Monero"(モネロ) - ニルスの暗号通貨日記

ZCASHの場合は、匿名化にzk-SNARK というプロトコルを用いているようです。

最近、さら改良された BulletProof というプロトコルが提案されています。 https://eprint.iacr.org/2017/1066.pdf

論文にBitcoinのコアメンバの名があります。

JSONRPC をpython で体験する

RPC(リモートプロシージャコール)とはRESTと同じような、
特定フォーマットのHTTPリクエストを受け取り、レスポンスを返すプロトコルの一種です。
フォーマットには XML, JSON, protocol buffer, messagepack などあります。 最後の2つはバイナリフォーマットです。
最も簡単なjson-rpcを体験してみましょう。

環境: macOS

こちらのチュートリアルをそのまま使ってみます。

Quickstart — jsonrpc 1.10.8 documentation

pip というpython 用のパッケージマネージャー(rubyでいうところのbundle)はインストールされているものとします。

このチュートリアルで使われているパッケージをすべてインストールします。

$ pip install json-rpc
$ pip install werkzeug
$ pip install requests
$ pip install json-rpc
Collecting json-rpc
  Downloading json_rpc-1.10.8-py2.py3-none-any.whl (40kB)
    100% |████████████████████████████████| 40kB 371kB/s 
Installing collected packages: json-rpc
Successfully installed json-rpc-1.10.8
$ pip install werkzeug
Collecting werkzeug
  Downloading Werkzeug-0.14.1-py2.py3-none-any.whl (322kB)
    100% |████████████████████████████████| 327kB 1.3MB/s 
Installing collected packages: werkzeug
Successfully installed werkzeug-0.14.1
$ pip install requests
Collecting requests
  Downloading requests-2.18.4-py2.py3-none-any.whl (88kB)
    100% |████████████████████████████████| 92kB 946kB/s 
Collecting certifi>=2017.4.17 (from requests)
  Downloading certifi-2018.1.18-py2.py3-none-any.whl (151kB)
    100% |████████████████████████████████| 153kB 675kB/s 
Collecting chardet<3.1.0,>=3.0.2 (from requests)
  Downloading chardet-3.0.4-py2.py3-none-any.whl (133kB)
    100% |████████████████████████████████| 143kB 999kB/s 
Collecting urllib3<1.23,>=1.21.1 (from requests)
  Downloading urllib3-1.22-py2.py3-none-any.whl (132kB)
    100% |████████████████████████████████| 133kB 839kB/s 
Collecting idna<2.7,>=2.5 (from requests)
  Downloading idna-2.6-py2.py3-none-any.whl (56kB)
    100% |████████████████████████████████| 61kB 889kB/s 
Installing collected packages: certifi, chardet, urllib3, idna, requests
Successfully installed certifi-2018.1.18 chardet-3.0.4 idna-2.6 requests-2.18.4 urllib3-1.22

server.py client.py を作成し、実行します。

$ python server.py 
 * Running on http://localhost:4000/ (Press CTRL+C to quit)

これを実行します。

$ python client.py 

標準出力にechoされました。

127.0.0.1 - - [15/Feb/2018 20:35:32] "POST /jsonrpc HTTP/1.1" 200 -

参考: 【Python】RPCライブラリ・フレームワークまとめ - Qiita

ビットコインにおけるブルームフィルターとマークルツリーパス

現時点(2018年2月)において2009年から作られたビットコインのブロックの数(=ブロック高)は、
こちら Bitcoinブロックエクスプローラ - ブロックチェーン をみるとわかるように、 508786 です。
最新の4つのブロックを見ると、一つのブロックには、200 ~ 1600 個のトランザクションが含まれていました。

ビットコインフルノードはトランザクション情報全てを持つ必要があるため、現時点で、
500GBほどのディスクを必要としますが*1、フルノードでないビットコインノードである、
ウォレットノード、マイニングノードなどの軽量ノード(SPVノード)では、すべてのトランザクション情報を持つ必要はありません。
しかし、あるアドレスから送信、受信したあるトランザクションがどこのブロックに含まれるかを効率よく知る必要があります。
SPVノードはすべてのトランザクション情報を持つフルノードに対してトランザクションIDを送り、
フルノードは、それをすべてのブロックから検索し、見つかれば、そのトランザクションの情報をSPVノードに送り返します。
この仕組みを使えばSPVノードはすべてのトランザクション情報を持つ必要がありません。

あるトランザクションがどのブロックに含まれるか、高速に検索するには事前にインデックスをつけておけばよいです。
これを実現するための仕組みがマークルツリーパスです。

マークルツリーパス

マークルツリーパスに関してネット上に分かりやすい解説が見つからなかったので、
(マークルツリーの解説はありますが。。)
オライリーのmastering bitcoin の解説か日本語訳した無料版の資料 https://www.bitcoinbook.info/translations-of-mastering-bitcoin/ を参照するのがよさそうです。

C++が分かる方はオリジナルソースを読むのもいいかと思います。
該当ロジック部分だけであれば、量的にはわずかです。
GitHub - bitcoin/bitcoin: Bitcoin Core integration/staging tree

マークルツリーの実装ヘッダはこれだけです。
https://github.com/bitcoin/bitcoin/blob/master/src/merkleblock.h

マークルブロッククラスCMerkleBlockは一つのブロック内にある複数のトランザクションとその位置(マークルパス)を表現したものです。
SPVノードとフルノード間でやりとりされるのは、このクラスの値をバイナリでシリアライズしたものになります。

CMerkleBlockクラスのシリアライズしている関数の実装を見てみましょう。

class CPartialMerkleTree {
protected:
    /** the total number of transactions in the block */
    unsigned int nTransactions;
    /** node-is-parent-of-matched-txid bits */
    std::vector<bool> vBits;
    /** txids and internal hashes */
    std::vector<uint256> vHash;
    ...
}

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
    // トランザクションの数
    READWRITE(nTransactions);
    // トランザクションIDのarray
    READWRITE(vHash);
        
    std::vector<unsigned char> vBytes;
    if (ser_action.ForRead()) {
        // read
        READWRITE(vBytes);
        CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));
        us.vBits.resize(vBytes.size() * 8);
        for (unsigned int p = 0; p < us.vBits.size(); p++){
            us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;
        }
        us.fBad = false;
    } else {
        // write
        // トランザクションIDのarrayに対するビットOn/Offをバイトにしたもの
        vBytes.resize((vBits.size()+7)/8);
        for (unsigned int p = 0; p < vBits.size(); p++){
            vBytes[p / 8] |= vBits[p] << (p % 8);
        }
        READWRITE(vBytes);
    }
}

コメントに書いていますが、シリアライズされているのは、このクラスのメンバ変数である
nTransactions, vHash, vBits の値だけを使っています。
例えば、対象トランザクションが一つだけ、このブロックに含まれるトランザクションの数が14個の場合の構造を図にしたものがこちらです。

f:id:pebble8888:20180812220229p:plain:w500

vBitsはそのノードの子孫に対象トランザクションが含まれる場合 true です。
枝の場合 true, 葉の場合 false とも言えます。
vHashはそのノードの子孫に対象トランザクションが含まれない場合そのノードのハッシュです。
一番下のノードはトランザクションIDです。
vHashの値が枝のハッシュ値なのか、一番下のノードの葉(トランザクションID)なのかどうかは
Depth(最初の頂点から枝分かれの数)によって判別できます。

vHashの要素数はツリーの末端の葉(leaf)の数となります。この例では 5 です。
vBitsの要素数はツリーの末端の葉の数+ツリーの頂点の数となります。この例では 5+4 = 9 です。

vHash,vBitsのインデックスの順序づけは、もっとも深い葉(トランザクションID)の先頭側、depth が浅い方が先頭側となっています。

CMerkleBlock の利用箇所

CMerkleBlockが利用されているのは、net_processing.cpp, rpc/rawtransaction.cpp, wallet/rpcdump.cpp の3つのソースファイルですが(残りは単体テスト), 簡単そうな、rpc/rawtransaction.cppをみてみます。

CMerkleBlock が使われているのは、以下2つの関数です。

// @param  一つのブロック内にあることを前提としたトランザクションIDの配列
// @return 指定されたトランザクションの情報を含むマークルブロックをHEX文字列にしたもの
UniValue gettxoutproof(const JSONRPCRequest& request)

// @param gettxoutproof で返されたマークルブロックHEX文字列
// @return 指定されたマークルブロックがブロックチェーンに含まれるvalidなものかどうか
UniValue verifytxoutproof(const JSONRPCRequest& request)

どちらも引数を見ると分かるようにJSONRPCのリクエストに応答を返すものです。
gettxoutproof はフルノード上で、指定したトランザクションのunspentなアウトアップトランザクションが存在するブロックを、
ブロックチェーン内を検索します。これにはディスクアクセスを必要とします。
verifytxoutproof はマークルブロック内のマークルパスのハッシュを合成したものがマークルルートハッシュに一致するかどうかを確認します。 もし、クラッカーが不正なトランザクションをこのブロックに追加されたものとして利用しようとした場合、
マークルルートハッシュが異なる値を持つので、ブロックチェーンの検証が行われた際に不正データとして破棄されます。

vHashの値に加えて、vBitsの値が必要なのは、マークルルートハッシュを計算するために、vHashをどの順番で合成していけば良いのか順序を知る必要があるためです。
ここでの例でのトランザクション数は14なので、height は4となります。
vHashの値の個数は height + 1 (=5) vBitsの値の個数は 2 * height + 1 (=9) となります。 トランザクション数が大きくなっても、heightが大きくなる速さはlog2なので、シリアライズ結果のデータサイズはそれほど大きくはならないことが分かります。

ブルームフィルター

ブルームフィルターとは、一般にはデータベースなど、大量のデータを扱う際に用いられる、インデックス手法の一種です。

ググって見つかったブルームフィルターに関する解説はこちら。

ブルームフィルタ - Wikipedia

ビットコインの技術 BloomFilter プログラミングJava

Scalable Bloom Filtersとは一体....?

C++でブルームフィルタを実装する方法 | POSTD

ブルームフィルターの実装ヘッダはこれだけです。 https://github.com/bitcoin/bitcoin/blob/master/src/bloom.h

あるビットコインアドレスが現在所有してしているコイン量を知るには関連するトランザクション情報全てを全ての ブロックからとってくる必要がありますが、その検索方法だと、SPVノードからの問い合わせを受けつけるフルノードはそのSPVノードが利用しているビットコインアドレスを特定できる事になります。
これに若干の秘匿性を持たせる仕組みがブルームフィルターです。

参考:
作って学ぶBitcoin!ゼロから作るSPVウォレット

https://bitcoin.org/en/developer-reference#parsing-a-merkleblock-message

ビットコインとブロックチェーン:暗号通貨を支える技術

ビットコインとブロックチェーン:暗号通貨を支える技術

*1:ブロックサイズは1MBなので、フルノードは 1MB* 508786 = 508GBのディスクが必要ですが、 ブロックヘッダサイズは80バイトですし、1トランザクションのサイズも数十バイトなので、SPVノードには大量のディスクは必要ありません。

2017年買ってよかったモノベスト3

2017年買ってよかったモノベスト3です。

第3位 MacBookPro 2017 13inch

www.apple.com

f:id:pebble8888:20180209203332j:plain:w300 f:id:pebble8888:20180209203345j:plain:w300

今まで、iOSアプリ開発用には MacBook Air を使っていましたが、Storyboardを開くのにメモリ不足で、
きつくなってきていたので、入手を決めました。
Storyboardを開く時に時間がかかることもなくなりました。

vim を使う際、Escキーがタッチバーなのはきついので、タッチバーなしモデルにしました。
またカフェで作業することもあるので、13inch にしました。 キーボードのタッチが MacBook Air に比べてかなり浅くなっています。
私は慣れましたが、肩こりがひどくなり、旧MacBook Proに戻したという方もいるのでしっかり確認しましょう。

USB-C 用のケーブルもいくつか購入しましたが、特に問題はありませんでした。

第2位 コードレスクリーナー Dyson V7 Fluffy

https://www.dyson.co.jp/dyson-vacuums/cordless/dyson-v7/dyson-v7-fluffy-hepa.aspx?mkwid=sMTbmYsGD_dc&pcrid=96857714921&pkw&pmt&utm_source=google&utm_term&utm_medium=cpc&utm_campaign=Dyson_JP_JP_PLA_FC&utm_content=MTbmYsGD&gclid=CjwKCAiAqvXTBRBuEiwAE54dcK7D-f36MQqI8Y9TkMfkzJHJt9lVlGaXaEsdvvYQx1QX5DWG_Vm1JxoCQK0QAvD_BwE&gclsrc=aw.ds&dclid=CLi74r3rmNkCFRCavAodN3IGrwwww.dyson.co.jp

f:id:pebble8888:20180209203153j:plain:w300 f:id:pebble8888:20180209203142j:plain:w300

ご存知、ダイソンのフローリング用コードレスクリーナーです。
床を掃除するのが楽しくなりました。
騒音も小さめなのが気に入っています。
女性が使うには少し重いかもしれないので、重さは店頭で確認しましょう。

第1位 コイズミ照明 KOIZUMI LED シーリング

webcatalog.koizumi-lt.co.jp

f:id:pebble8888:20180209203426j:plain:w300 f:id:pebble8888:20180209203404j:plain:w300

天井用の照明です。
少し値段がお高めですが、手元のリモコンで、昼間は寒色、夜は暖色に変更でき、消灯、点灯も可能です。
さらに、リモコンでオフした後、壁のスイッチをオフ、オンすると点灯するのが便利です。

クラウドマイニング HashFlare で SHA256 (BTC) にいくらか突っ込んでみた(2018年2月)

クラウドマイニングやってみたいなーという簡単な気持ちで、HashFlare のSHA256 (BTC) に少額を突っ込んでみました。
HashFlareはスコットランドの会社らしいです。

メリット、デメリット

マイニング機材の購入維持、マシンの騒音を気にする必要がないというのが、
自前マイニングに対するメリットです。
逆にマイニング会社の倒産、盗難などがデメリットになります。

購入

買ったのはコレ、SHA256 つまり、ビットコイン(BTC)のマイニングです。

f:id:pebble8888:20180203111639p:plain:w200

クレジットカードで日本円、又はBTCで購入することもできます。
期限は1年間で一括払いです。
購入予約をして、支払いするとそれが完了するようになっています。
支払いしないと、数時間でキャンセル扱いになるようです。

2 TH/s 分を購入してみました。
お値段は 10 GH/s で$2.2なので、
2000GH/10GH*$2.2 = $440です。

BTCで購入したので、0.0411 BTC を送金しました。
これで1年間、BTC採掘された分からメンテナンス手数料を引いた分が毎日溜まっていきます。
1年間で0.0411を上回ってくれないと赤字です。

メンテ手数料は0.0035$ / 10 GHs / 24h
となっているので、2TH/sの場合は、
0.0035$ * 2000GH / 10GH = $0.7
一日あたり、およそ70円です。

初日の結果

初日の結果です。
f:id:pebble8888:20180203111356p:plain:w600

0.00020281 BTC (1BTC=$9,945として約$2.0)がその日に採掘された量、
メンテ手数料がBTC建で、0.00007182 BTC 引かれ、
一日の利益が 0.00013099 BTC
仮にこの採掘量が一年間続いた場合、0.00013099BTC * 365 = 0.0468 BTC となり、
回収率は0.0468/0.0411 = 113.8% となります。
なんというか微妙な結果になりそうです。
赤字でないだけましですが。

ちなみにこの画面右端の利益予測はメンテ手数料が含まれていませんのでご注意下さい。

f:id:pebble8888:20180203111344p:plain:w600

ちょっと不親切やなあと思います。

マイニング時は、仮想通貨取引とは異なり、毎日、利確している状態となるので、
毎日のBTC価格で利益を計算する必要があります。
HashFlareにはマイニングデータをダウンロードする機能はなさそうなので、確定申告時に備えて、
一ヶ月に1回程度は自前帳簿を更新しておかないと、その頃になってヒーヒーいうことになりそうです。

購入は経費に含めることができる

最初の購入費用(私の場合0.0411BTC)は、確定申告時は、経費に含めることができるようです。

再投資機能

HashFlareには入手したBTCをさらにハッシュレート購入に充てる機能があり、
回収速度を上げることができるようですが、帳簿付けがさらに面倒になるので、 面倒なことが嫌いな私はやりません。

SHA256以外のマイニング

SHA256(BTC)以外に、SCRYPT(LTC)、ETHASH(ETHEREUM)、EQUIHASH(ZCASH)、X11(DASH)のマイニングもできるようですが、
どのくらいの回収率かは不明です。

まとめ

私にとっては帳簿付けがメンドくさすぎるので、これは向いてないなあと思いました。

クラウドマイニングに高額をつぎ込むのはリスクが高い投資です。
失っても問題ない余剰資金でやりましょう。