憂鬱な午後のひととき


4月28日_

(へぇな会社)フィードテイラー 本業のために、副業のススメ

新聞を読んでいたら, おお, 以前同じ会社で働いていた人の会社やないか. すごいなあ. ちなみにサイボウズも少し前から副業OKになってる.

4月27日_

UTF-16用strstrなど

SSE4.2の文字列処理命令を使ったCライクな文字検索ライブラリ(string.hpp). ちまちまとUTF-16対応を進めてる. 恐らくwcslenなどはVCのライブラリを使えばよいが, std::stringライクなNULLターミネートされない範囲指定バージョンは無いので自分で作ってる. パラメータがbyte長ではなく文字の長さなのでときどきはまってるが大体できてきた. テストが酷いことになってるのできれいに書き直して漏れが無いようにしたい.

4月25日_

大学のときの知り合いと会う

前回は3年半年前だった. そんなに経ってたっけ. 東京でちょっと打ち合わせをしたいときに利用できるラウンジが品川にあるらしい. へぇ.

4月24日_

楕円曲線上の鍵共有サンプルコード

以前からちまちまと作ってるライブラリgithub.com/herumi/mieを使うと ecdh_smpl.cppのようにかける.

先日公開されたゲノム情報研究センターの楕円エルガマル暗号のライブラリでも使われている.

4月18日_

会社の食事会

本社の合同食事会に参加させてもらった. こういうのは初めてだ. ありがたい. 恵比寿のロブションという普段なら見もしない高級そうなお店. ここはお城か? お肉がおいしかった.

4月16日_

『下妻物語』(嶽本野ばら)

昔読んだし, 映画も見たけどまた読んでみた. やっぱり面白い. 借りたものは返さない, 友達はつくらないという桃子は凄い.

『脊梁山脈』(乙川優三郎)

23歳で終戦を迎えた主人公が戦後どうやって生きるのかを模索する. 復員列車の出だしや木地師に興味を持ってそれを調べるところなどはとてもよかった. 文章がすばらしい. ただ周りの女性の強さに対して主人公のヘタレっぷりが読んでていらいらする.

4月11日_

std::random_deviceとrdrand

rdrandはIvy bridge以降のCPUに搭載された乱数発生命令. シミュレーション用ではなく, 暗号論的に安全な乱数が必要な時に使うものとして用意された. これがどれぐらいの速度なのか計ってみた(rdrand.cpp).

XorShiftとstd::mt19937と比較してみる. まずはSandy Bridgeで

rand benchmark on Sandy Bridge[clk]
XorShift mt19937 random_device
Linux gcc-4.8.2 9.60 13.09 874
Win7 VC2013 5.67 9.84 2309

XorShiftはさすがに速い. MTもよい. SFMTならもっと速そうだ. もちろん, 暗号論的擬似乱数が必要なときにXorShiftやMTは使えないので念のため.

random_deviceはかなり遅い. Windows版は特に遅い. この遅さの理由と改善方法は後で触れる. 次にHaswellで

rand benchmark on Haswell[clk]
XorShift mt19937 random_device rdrand
Linux gcc-4.8.1 7.87 9.78 310 291

rdrandはintrinsic関数を使えば

uint32_t use_rdrand()
{
    for (int i = 0; i < 10; i++) {
        uint32_t x;
        if (_rdrand32_step(&x)) return x;
    }
    fprintf(stderr, "_rdrand32_step err\n");
    exit(1);
}

こんな感じでお気軽に使える. _rdrand32_step(rdrandのintrinsic関数)は乱数を生成するためのエントロピーが足りなかったときエラーを返す. たまるまでしばらく待つ. ちょっと試した限りではrdrandの数百万回連続呼び出し程度では_rdrand32_stepがエラーを返すことはなかった.

さて, Haswellのrandom_deviceはSandy Bridgeの2倍以上速い. これはなぜだろう. コードを追いかけるとgccのrandom_deviceはrdrandが使えるときそれを使っていた. つまり殆ど上記コードと変わらないものだった.

これはIntelがrdrandにバックドアを仕掛けていたときのことを考える人にはいやなことかもしれない. 一応random_deviceに"/dev/urandom"というトークンを渡すと通常の/dev/urandomを使うモードに切り換えることができる.

uint32_t use_random_device()
{
    static std::random_device rd("/dev/urandom");
    return rd();
}

心配性な人はそちらをつかえばよいだろう. なおそのときの速度は860clk程度でSandy Bridgeとほぼ同じだった.

なお, 自分で"/dev/urandom"をopenしてreadしたい場合, システムコールのopen, readを使うよりはCライブラリのfopen, freadを 使う方がずっと速いことに注意. これは後者が大きめのバッファをとってそれを切り崩すからである.

ちなみにWindows版のrandom_deviceは内部でrand_sというライブラリ関数を呼んでいる. そしてこの関数の実装ではCryptGenRandom等が使われている. Windows上のrandom_deviceがgccに比べてずっと遅いのはこの関数の初期化処理などが重たいためなようだ. 実際, それらのAPIを自分で呼び出し, 大きめにバッファをとって切り崩すことをしてみた(random_generator.hpp).

すると, Sandy Bridgeでrandom_deviceと同等と思われる(多分:もしかしたらパラメータが違うのかもしれない)処理が71clkと30倍以上速くなった. これはLinuxの/dev/urandomより10倍ぐらい速い.

4月8日_

OpenSSL Heartbleed

影響が大きいらしい. ssl/d1_both.cの変更点を見てみる(一部).
バグあり版.

    unsigned int padding = 16; /* Use minimum padding */

    /* Read type and payload length first */
    hbtype = *p++;
    n2s(p, payload);
    pl = p;

    if (s->msg_callback)
            s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
                    &s->s3->rrec.data[0], s->s3->rrec.length,
                    s, s->msg_callback_arg);

    if (hbtype == TLS1_HB_REQUEST)
            {
            unsigned char *buffer, *bp;
            int r;

            /* Allocate memory for the response, size is 1 bytes
             * message type, plus 2 bytes payload length, plus
             * payload, plus padding
             */
            buffer = OPENSSL_malloc(1 + 2 + payload + padding);

修正版.

    unsigned int padding = 16; /* Use minimum padding */

    if (s->msg_callback)
            s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
                    &s->s3->rrec.data[0], s->s3->rrec.length,
                    s, s->msg_callback_arg);

    /* Read type and payload length first */
    if (1 + 2 + 16 > s->s3->rrec.length)
            return 0; /* silently discard */
    hbtype = *p++;
    n2s(p, payload);
    if (1 + 2 + payload + 16 > s->s3->rrec.length)
            return 0; /* silently discard per RFC 6520 sec. 4 */
    pl = p;

    if (hbtype == TLS1_HB_REQUEST)
    ...

n2s()は2byteデータを読むマクロ. 関数の最初でpayloadを読んでいた部分がrrec.lengthのサイズを確認してから読むように変更された.

そりゃそうだろうなあ. ところで1とか2とかのマジックナンバーを直接書いてると名前をつけた方がいいと思ってしまう. というかせっかくunsigned int padding = 16;って定義してるのに + 16 なのは焦ってたのかな. まあ, こういうのは他人が見るといくらでもいちゃもんはつけられてしまうものなので止めとこう.

4月3日_

バグ

この半年ぐらいいっしょに作業してたプロジェクトの中間発表に参加しててメインの人がデモを始めたらサーバが固まって苦笑するしかなかった. 何日か前から何度か, 当日の始まる前にも動くことを確認してたのになあ.

後で調べたら, 作ってたもの自体が悪いのではなく, 発表時の操作ミスでそれが呼び出してる別のモジュールの潜在的なバグを出してしまったせいだった.

まあ, それも含めたトータルな試験はこれからやっていく予定なのでそういうのをどんどんつぶしていかないと.

4月1日_

『ペンギン・ハイウェイ』(森見登美彦)

ちょっと小生意気だけど真剣に研究してる小学4年生が主人公. 秘密基地や探検のあたりでなぜか『誰も知らない小さな国』(佐藤さとる)を思い出す. あちらの現代版みたいな感じ(と思ってしまった).

話自体は単調なんだけど, 個別のエピソードやフレーズで気に入ったものが多い. プールで主人公がいじめられたときの対応もよいが, それに対するお母さんのコメントも凄い. お父さんにノートのつけ方や問題解決の方法を教わってるシーンもとてもすばらしいと思う.


御意見は光成滋生<herumi@nifty.com>までお願いします