iPX社員によるブログ

iPX社員が"社の動向"から"自身の知見や趣味"、"セミナーなどのおすすめ情報"に至るまで幅広い話題を投下していくブログ。社の雰囲気を感じ取っていただけたら幸いです。

UE4で強化学習環境を動かし、学習状況を可視化する(Part1)

前書き

お久しぶりです。iPXのabikoです。
最近急激に気温が上がり、真夏日を記録する所も出てきました。
近年春といえるような過ごしやすい日が少なくなっていることを寂しく感じます。
今後も気温の変動が激しそうです、皆さんお体に気をつけてお過ごしください。

今回の記事は

今回はUnrealEngeie4(以下UE4)と強化学習を組み合わせた記事にしたいと思います。
ずばり、UE4強化学習環境(CartPole)を動かし、学習状況を可視化する、です。

※といいながら、学習自体は行いません。可視化がメインです。
 強化学習環境にはOpenAI Gymを使用し、行動はランダムで与えます。

事の始まり

最近ではUE4機械学習に触れる機会が多くなりました。
そんな中、社内で「UE4ってPythonで書けないんですかね?」という話題が。

気になって調べてみると「UnrealEnginePython」というOSSプラグインを発見しました。
GitHub - 20tab/UnrealEnginePython: Embed Python in Unreal Engine 4
下記のページを見るに、Pythonコードにてアクターの座標移動まで実現できています!
UE4でPythonを使ってみる - Qiita

キューブが天に上っていく様子を見て、私の頭の中では下図が再生されました。

f:id:ipx-writer:20190506195722g:plain
CartPole

そう、かの有名なCartPoleです。機械学習の多くはPythonで書かれています。
Pythonで記述でき、ゲームプレイ時にキューブを動かすこともできるのであれば、UE4上で強化学習を実行するに止まらず、その学習状況の可視化もできてしまうのでは!と思い立ったのです。

それでは、さっそく試していきます。

準備の前に...

今回UE4および、Pythonのインストールについては割愛します。

参考

それぞれ下記のページからダウンロードすることができます。
UE4
www.unrealengine.com
Python
www.python.org

使用環境

OS WIndows 10
UE4 4.21.2
Python 3.6.6
UnrealEnginePython 20181128 Binary Releases

UnrealEnginePythonについて、当初はPythonが同梱(embedded)されているもので試してみたのですが、pipでエラーが出るなど苦戦したため、非同梱版を使用するようにしました。
→UnrealEnginePython_20181128_4_21_python36_win64.zip

そのため、Pythonを端末内に別途用意します。
今回は公式ページからダウンロード・インストールしたPythonを使用しています。

Pythonの下準備

UnrealEnginePythonのPython同梱版を使用しない場合、環境変数のPATHにインストールされているPythonのパスを設定する必要があります。
Pythonをデフォルトでインストールした場合には下記のパスを設定します。

C:\Users\****\AppData\Local\Programs\Python\Python36
C:\Users\****\AppData\Local\Programs\Python\Python36\Script

続いてコマンドプロンプトを起動してOpenAI Gymをインストールします。

$ pip install gym

UnrealEnginePythonをUE4プロジェクトに適用

UnrealEnginePythonプラグインをプロジェクトに適用する手順が下記になります。

1.空のブループリント(BluePrint=以下BP)プロジェクトを作成
f:id:ipx-writer:20190506200032p:plain
2.作成したプロジェクトルート直下にPluginsフォルダを作成
f:id:ipx-writer:20190506200051p:plain
3.UnrealEnginePythonプラグインをダウンロードして解凍
Releases · 20tab/UnrealEnginePython · GitHub
→「20181128 Binary Releases」の「 UnrealEnginePython_20181128_4_21_python36_win64.zip」をダウンロード

4.解凍結果のフォルダ配下にある「UnrealEnginePython」フォルダを「2. 」で作成したPluginsフォルダに配置
f:id:ipx-writer:20190506200111p:plain

5.プロジェクトを起動
Python環境変数が正しく設定されていない場合、起動時にエラーとなる

6.ウィンドウ>Python Editor のメニューが表示されていることを確認
f:id:ipx-writer:20190506200150p:plain

これでUnrealEnginePythonを使用する準備ができました。

UE4で可視化したいコード

今回UE4で実行&可視化したいコードはこちらになります。

import gym
env = gym.make('CartPole-v0')

for episode in range(50):
    observation = env.reset()
    done = False
    while not done:
        env.render()
        action = env.action_space.sample()
        observation, _, done, _ = env.step(action)

次の行動(右・左)をランダムに与え続けるコードになっています。

参考

CartPole環境の詳細についてはこちらを参照してください。
CartPole v0 · openai/gym Wiki · GitHub

Python Editorの動作確認

上記コードをPython Editorで実行してみます。

1.「ウィンドウ>Python Editor」を押下し、Python Editorを起動
2.上部メニューの「New」を押下してスクリプトファイルを作成
3.右下のエディタ部に上記コードをペースト
4.「Save」を押下して保存
f:id:ipx-writer:20190506201127p:plain
※Ctrl+S での保存が効きません。
 本格的に使用していく場合、VSCodeなど別のエディタを使ったほうがよさそうです。

※また、ソースコードに変更を加えたり、新たにファイルを追加した場合に下図のようなメッセージが出ます。「インポート」を押下し更新を反映しておきます。
f:id:ipx-writer:20190506201210p:plain

5. 「Execute」を押下し、コードを実行

f:id:ipx-writer:20190506203508g:plain
CartPole
無事実行できました!

次回

ここまでで一旦休憩です。
次回以降、ゲームプレイによって動作するコードに書き換え、状況を可視化できるように仕立てていきます。

それではまた、お会いしましょう。

国際社会と思わずの攻撃

「サンキュー!」

それを聞いた僕がドアを開けたままに一瞬フリーズしました。
良かったことに、セリフを言ってくれた方が一回も振り向かずに通って、僕がすごくムッとしている顔が誰にも見られなさそうでした。

しかし何で腹が立ったの?僕が客先で食堂のドア開けた時に後ろの所員さんを先に通した。【通っていた小学校は「先にドアに着いた者は最後に通る」のようなルールがあって、嫌でも一生についてしまったみたい(汗)】 それにお礼されただけでした。皮肉などもなかったから、お礼にムカつく権利がないはずです。それはわかってもムカつきました。それはわかったのでムカつきました。

今回のiPXブログ担当のベーカーです。今回のテーマが個人的でちょっと暗いかもしれないですが、よろしくお願いします。

続きを読む

WindowsのVisual Studio Code上でC++環境セット

どうも、iPXのパルハットです。最近業務で機械学習関連の案件にかかわることが増えています。その場合プログラム言語として主にPythonを使っていましたが、TensorRT、ROS等を用いる場合にはC++も登場しますので、使う機会しばしばあります。最近、個人のWindowPCにC++を実行できる環境のセットアップしてみました。そこで今回のブログにその設定手順を乗せることにしました。エディタはVSCodeを使用しています。

MinGWのインストール

MinGW(Minimalist GNU for Windows)GNUツールチェーンのWindows移植版です。

インストール手順

  1. MinGWをダウンロードしてから、インストーラを実行します。デフォルト設定を従ってインストールをします。f:id:ipx-writer:20190504184025p:plainf:id:ipx-writer:20190504184424p:plainf:id:ipx-writer:20190504184451p:plain
  2. 表示された画面からインストールするパッケージを選択して、メニューからinstallation->ApplyChangesをクリックします。以下が最小限の選択項目です。
    1. mingw-developer-toolkit-bin
    2. mingw32-base
    3. mingw32-gcc-g++
    4. mingw32-gdb-binf:id:ipx-writer:20190504185132p:plainf:id:ipx-writer:20190504185149p:plainf:id:ipx-writer:20190504185337j:plain
  3. 表示された画面のApplyをクリックすると変更項目でシステム構成が更新されます。最後の画面のcloseをクリックしてインストールを終了します。f:id:ipx-writer:20190504185553p:plainf:id:ipx-writer:20190504185603p:plainf:id:ipx-writer:20190504185613p:plain

Visual Studio Codeのインストール

Visual Studio Codeマイクロソフトによって開発されたプログラムソースコード用のエディタです。

インストール手順

  1. VSCodeをダウンロードしてから、インストーラを実行します。デフォルト設定を従ってインストールをします。f:id:ipx-writer:20190504190204p:plainf:id:ipx-writer:20190504190213p:plainf:id:ipx-writer:20190504190244p:plainf:id:ipx-writer:20190504190254p:plainf:id:ipx-writer:20190504190308p:plainf:id:ipx-writer:20190504190326p:plainf:id:ipx-writer:20190504190336p:plainf:id:ipx-writer:20190504190917p:plain
  2. VSCodeがエディタの設定
    1. c/c++Extensionの設定f:id:ipx-writer:20190504190805p:plain
    2. Code Runnerの設定f:id:ipx-writer:20190504191021p:plain
    3. テストコードを実装, エディタの上でマウスの右をクリックして、Run Codeをクリックして実装します。f:id:ipx-writer:20190504191247p:plainf:id:ipx-writer:20190504191334p:plain
  3. コードがちゃんとコンパイルできたことが確認できます。VSCodeターミナルからtest.exeのファイルが作成されたことが確認できます。これで環境のセットアップが終了になります。場合によって文字化けが発生したり、C++の環境パスが設定されなかったり等をありますので、注意してください。f:id:ipx-writer:20190504191919p:plain

まとめ

業務でLinuxPCを使っているので、C++コードが普通にコンパイルできていました。しかし、個人PCでもたまにテスト、調査などをやる時が発生しますので、今回がその手前として環境セットアップをしてみました。

海の中へ

アクティブに見えないけど意外とアクティブ代表
TCDのタキヤマです

GWは適当に予定を組んだところ、令和初日に伊勢神宮へ行くことになって
御朱印を貰うのに各2時間掛かって大変でした。

ということで、小難しい記事を書くのは柄じゃないので久しぶりに趣味の話にします。

続きを読む

趣味の話

ご挨拶

新緑まぶしい季節となりました。
皆様如何お過ごしでしょうか。

どうも、iPX川口です。

GWが間近に迫ってまいりました。
今年のGWは最大10連休とのことで、旅行に行かれる方も多いのではないでしょうか。
高速道路の渋滞も予想されるので、時間をずらしてピークを避ける工夫が必要ですよね。

かく言う私もGWは香川、愛媛旅行を予定しています。
人生初四国です。
香川県のうどんを楽しみにしています。
愛媛県では下灘駅などを観光する予定です。。

せっかくの休みなので事故の無いよう道中の運転に気をつけようと思います。
なにせ自家用車で栃木から香川へ向かうので。

本題

さて、趣味の話です。
6:4でインドア派の私ですが、しばしば旅行に行ったりします。
今年は伊豆、水戸(栃木から近いので日帰りもできますが)へ行きました。
水戸のあんこう偕楽園(梅が有名)の写真がこちらです。

あんこう

お店は 水戸の山水さん。

写真用に一度食材をテーブルまで運んでくれます。
稀に見た目が受け付けないという声も聞きますが、私にはたまらなく美味しそうにみえます。
f:id:ipx-writer:20190425225646j:plain
f:id:ipx-writer:20190425225640j:plain
その後厨房へ調理すると、こうなります。

どぶ汁

f:id:ipx-writer:20190425225702j:plain
 あん肝の溶けた味噌ベースの鍋です。
スープが濃厚で、塩気が少し強いものの野菜や魚の身と食べると丁度良くなります。
とてもおいしいです!
Wikipediaによると、
「名前の由来は、あん肝が溶け出して汁がどぶのように濁ることから、また、どぶには「すべて」という意味があり、アンコウのすべてを入れることから「どぶ汁」との説もある。」
とのこと。

あん肝

 濃い!舌触りが良い!美味い!
f:id:ipx-writer:20190425225757j:plain

偕楽園

f:id:ipx-writer:20190425225803j:plain
梅が有名なところですね。
少し梅の花見シーズンから外れましたが、咲いている花もありました。
こんな感じ。
f:id:ipx-writer:20190425225809j:plain

偕楽園内の竹林
f:id:ipx-writer:20190425225827j:plain


というように旅行(食事、観光)を楽しみました。

次回は香川、愛媛の紹介でしょうか。
お付き合いいただきありがとうございました。

では、また。

ストリーム暗号ChaCha20よる擬似乱数生成のRust実装について

近況

お久しぶりです。iPXのTCDの砂子です。 社員が増えてきたためかブログの記 事当番がなかなかまわってこないようなきがします。 以前に書いたのが 2018/07/29になるので半年ぶりになるのですね。

前回の記事を書いた時点では栃木在住だったのですが、本社勤務が決まった関 係で現在は東京都に引越しをしました。都内だとIT関連の勉強会なども通いや くすなり有益なことがおおいです。

さて、前回に引続きRust言語の話題となります。書籍なども一通り読み終え たのでかねてより目標にしていた疑似乱数生成の実装を行なってみました。

ChaCha20 stream cipher

どの疑似乱数生成器の実装しようかと考えているうちにGoogleの暗号化規格 「Andiantum」の記事が目にとまりました。

記事を読んでいるとその規格の一部にストリーム暗号ChaCha20が使用されて いることが分かります。ChaCha20はTLSの暗号方式にも採用されているようです。

ストリーム暗号とは音声通信や動画配信などを暗号化するために用 いられます。逐次発生するデータをその都度暗号化して流すので\"ストリーム\" が冠されていると覚えれば分かりやすいかと。

ちなみにブロック暗号はファイルなど大きさの定まったまとまりを暗号化す る暗号方式です。AESなどがこれにあたります。

疑似乱数にストリーム暗号が関係あるのか?となりますが、ストリーム暗号 はその実装で疑似乱数を発生するものがあります。そのためWikipediaのペー ジにもありますが疑似乱数を作るさいにストリーム暗号を利用ることがあり ます。

RFC8439 実装

開発者のサイトなどでC言語でかかれた参考ソースコードなどがありますが、 それをそのまま移植しては少々おもしろくありません。

そこでChaCha20の仕様はRFC8439 を参考にしました。途中までObsoleteされた RFC7539を参照していましたが、別記事などをみて間違いに気付きました。

ちなみにRFC8439の全部を実装するのではなく下記2章の途中までの実装しま す。

 1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4
     1.1. Conventions Used in This Document . . . . . . . . . . . . 5
 2.  The Algorithms . . . . . . . . . . . . . . . . . . . . . . . 5
     2.1. The ChaCha Quarter Round . . . . . . . . . . . . . . . . 5
     2.1.1. Test Vector for the ChaCha Quarter Round . . . . . . 6 
     2.2. A Quarter Round on the ChaCha State . . . . . . . . . . . 6 
     2.2.1. Test Vector for the Quarter Round on the ChaCha State 7 
     2.3. The ChaCha20 Block Function . . . . . . . . . . . . . . . 7 
     2.3.1. The ChaCha20 Block Function in Pseudocode . . . . . . 9 
     2.3.2. Test Vector for the ChaCha20 Block Function . . . . . 10 
     2.4. The ChaCha20 Encryption Algorithm . . . . . . . . . . . . 11 
     2.4.1. The ChaCha20 Encryption Algorithm in Pseudocode . . . 12 
     2.4.2. Example and Test Vector for the ChaCha20 Cipher . . . 12

今回はrustで開発するにあたりひとつのファイルでテストまで済ませていま す。再利用可能にするにはもうすこしモジュール構成などをしっかりしたほ うがよいのですが次の課題とします。

2.1. The ChaCha Quarter Round

これがこの暗号方式のキモになるラウンド関数です。ビット演算で情報を でたらめな状態にする関数です。

使われているビット演算は加算、排他的論理和(XOR)、回転(rotate)になり ます。

加算と回転はC言語での表現と異なるので注意が必要です。 加算は overflow_add を使います。戻値は加算した値とくりあがりのタプルになっ ているので0番目を指定します。因みに + をつかって実装すると 実行時にオーバーフローによるエラーとなります。循環シフトは符号無し 32bitにメソッドが予め存在するため特に問題ありません。

// 2.1.  The ChaCha Quarter Round

//    The basic operation of the ChaCha algorithm is the quarter round.  It
//    operates on four 32-bit unsigned integers, denoted a, b, c, and d.
//    The operation is as follows (in C-like notation):

//    1.  a += b; d ^= a; d <<<= 16;
//    2.  c += d; b ^= c; b <<<= 12;
//    3.  a += b; d ^= a; d <<<= 8;
//    4.  c += d; b ^= c; b <<<= 7;

fn quarter_round(mut a: u32, mut b: u32, mut c: u32, mut d: u32) -> (u32, u32, u32, u32) {
    a = a.overflowing_add(b).0;
    d ^= a;
    d = d.rotate_left(16);
    c = c.overflowing_add(d).0;
    b ^= c;
    b = b.rotate_left(12);
    a = a.overflowing_add(b).0;
    d ^= a;
    d = d.rotate_left(8);
    c = c.overflowing_add(d).0;
    b ^= c;
    b = b.rotate_left(7);
    (a, b, c, d)
}

2.2. A Quarter Round on the ChaCha State

こちらは2.1で実装したラウンド関数を16ワードの配列に適用する実装です。 chacha20のラウンド関数は4x4=16ワードの入力にたいして複数回適用します。こ の実装は16ワードのうち4ワードを指定してラウンド関数を実行します。

2.1でも関数で実装しましたが、関数呼出や配列ののコストなどが問題にな るためマクロ機能で実装したいのですが今回は対応しませんでした。

// 2.2.  A Quarter Round on the ChaCha State

//    The ChaCha state does not have four integer numbers: it has 16.  So
//    the quarter-round operation works on only four of them -- hence the
//    name.  Each quarter round operates on four predetermined numbers in
//    the ChaCha state.  We will denote by QUARTERROUND(x,y,z,w) a quarter-
//    round operation on the numbers at indices x, y, z, and w of the
//    ChaCha state when viewed as a vector.  For example, if we apply
//    QUARTERROUND(1,5,9,13) to a state, this means running the quarter-
//    round operation on the elements marked with an asterisk, while
//    leaving the others alone:

//       0  *a   2   3
//       4  *b   6   7
//       8  *c  10  11
//      12  *d  14  15

fn apply_quarter_round(x: usize, y: usize, z: usize, w: usize, words_16: Vec<u32>) -> Vec<u32> {
    let old_a = words_16[x];
    let old_b = words_16[y];
    let old_c = words_16[z];
    let old_d = words_16[w];

    let (new_a, new_b, new_c, new_d) = quarter_round(old_a, old_b, old_c, old_d);

    let mut ret = vec![0; 16];
    ret[..16].clone_from_slice(&words_16[..16]);
    ret[x] = new_a;
    ret[y] = new_b;
    ret[z] = new_c;
    ret[w] = new_d;

    ret
}

2.3. The ChaCha20 Block Function

このセクションは3つに関数を分割しました。

  • setup~key~
  • block~function~
  • serialized

setup~keyは鍵~、カウンタ、Nonceから内部で使用する16ワードを鍵を作り ます。実装ではビット演算にmemクレートのtrasmuteを使用している箇所が あります。これは組み込みデータ型間でビット単位での変換を実現してい ます。4つの符号無し8bitのデータ型u8を1つの符号無し32bitに変換してい ます。これはpremitiveな操作になるためunsafeブロックで囲みます。

fn setup_key(key: Vec<u8>, counter: u32, nonce: Vec<u8>) -> Vec<u32> {
    // The ChaCha20 state is initialized as follows:

    let mut state: Vec<u32> = vec![0; 16];

    // o  The first four words (0-3) are constants: 0x61707865, 0x3320646e,
    //    0x79622d32, 0x6b206574.
    state[0] = 0x6170_7865;
    state[1] = 0x3320_646e;
    state[2] = 0x7962_2d32;
    state[3] = 0x6b20_6574;

    // o  The next eight words (4-11) are taken from the 256-bit key by
    //    reading the bytes in little-endian order, in 4-byte chunks.
    for i in 0..8 {
        let idx_state = i + 4;
        let idx_key = 4 * i;

        unsafe {
            state[idx_state] = mem::transmute::<[u8; 4], u32>([
                key[idx_key],
                key[idx_key + 1],
                key[idx_key + 2],
                key[idx_key + 3],
            ]);
        }
    }

    // o  Word 12 is a block counter.  Since each block is 64-byte, a 32-bit
    //    word is enough for 256 gigabytes of data.
    state[12] = counter;

    // o  Words 13-15 are a nonce, which should not be repeated for the same
    //    key.  The 13th word is the first 32 bits of the input nonce taken
    //    as a little-endian integer, while the 15th word is the last 32
    //    bits.
    for i in 0..3 {
        let idx_state = 13 + i;
        let idx_nonce = 4 * i;

        unsafe {
            state[idx_state] = mem::transmute::<[u8; 4], u32>([
                nonce[idx_nonce],
                nonce[idx_nonce + 1],
                nonce[idx_nonce + 2],
                nonce[idx_nonce + 3],
            ]);
        }
    }

    state
}

block~functionはラウンド関数をsetupkeyで作成された16ワードに8回適~ 用します。そして、適用後の値と適用前の値を排他的論理和を取得します。

fn block_function(key: Vec<u8>, counter: u32, nonce: Vec<u8>) -> Vec<u32> {
    // The ChaCha20 state is initialized as follows:

    let mut state = setup_key(key, counter, nonce);

    let mut working_state = state.clone();
    for _ in 1..=10 {
        working_state = apply_quarter_round(0, 4, 8, 12, working_state);
        working_state = apply_quarter_round(1, 5, 9, 13, working_state);
        working_state = apply_quarter_round(2, 6, 10, 14, working_state);
        working_state = apply_quarter_round(3, 7, 11, 15, working_state);
        working_state = apply_quarter_round(0, 5, 10, 15, working_state);
        working_state = apply_quarter_round(1, 6, 11, 12, working_state);
        working_state = apply_quarter_round(2, 7, 8, 13, working_state);
        working_state = apply_quarter_round(3, 4, 9, 14, working_state);
    }

    for i in 0..16 {
        state[i] = state[i].overflowing_add(working_state[i]).0;
    }

    state
}

最後にserializedを行ないます。

fn serialized(arr32: Vec<u32>) -> Vec<u8> {
    let mut serialized: Vec<u8> = vec![0; arr32.len() * 4];
    for i in 0..16 {
        unsafe {
            let arr8 = mem::transmute::<u32, [u8; 4]>(arr32[i]);
            serialized[i * 4] = arr8[0];
            serialized[i * 4 + 1] = arr8[1];
            serialized[i * 4 + 2] = arr8[2];
            serialized[i * 4 + 3] = arr8[3];
        }
    }

    serialized
}

2.4. The ChaCha20 Encryption Algorithm

前述の3つの節の関数を使用して暗号化を実装します。

平文を64ワード毎に8ワードの鍵、4ワードのカウンタと4ワードのナンスで 生成した疑似乱数をXOR演算で暗号化してゆきます。

fn chacha20_encrypt(key: Vec<u8>, counter: u32, nonce: Vec<u8>, plaintext: Vec<u8>) -> Vec<u8> {
    let mut encrypted_message = vec![0; plaintext.len()];

    for j in 0..(plaintext.len() / 64) {
        let key_stream = serialized(block_function(
            key.clone(),
            counter + j as u32,
            nonce.clone(),
        ));
        let block = &plaintext[j * 64..=(j * 64 + 63)];

        for k in 0..64 {
            encrypted_message[j * 64 + k] = block[k] ^ key_stream[k];
        }
    }
    if plaintext.len() % 64 != 1 {
        let j = plaintext.len() / 64;
        let key_stream = serialized(block_function(
            key.clone(),
            counter + j as u32,
            nonce.clone(),
        ));
        let block = &plaintext[j * 64..plaintext.len()];

        for k in 0..plaintext.len() % 64 {
            encrypted_message[j * 64 + k] = block[k] ^ key_stream[k];
        }
    }   
}

疑似乱数生成

さて、実装も一通りすんだところで疑似乱数の生成に取り掛かります。上記 のRFC8439では暗号化の仕様を定めています。疑似乱数生成の仕様ではあり ません。

疑似乱数を生成する方法はrustのrandクレートを参考にすることにしました。 また、この機能で生成した乱数を実装が正しくできたかの確認につかいます。

  • impl BlockRngCore for ChaChaCore
  • impl SeedableRng for ChaChaCore

ChaCha20の暗号処理で使用する下記3つの変数をそれぞれ下記のように割り 当てます。

  1. Key == Seed
  2. Nonce == 0
  3. conter == 乱数を生成でインクリメント

先ず、randクレートで正解の乱数を作成します。

use rand::{ChaChaRng, Rng, SeedableRng};

fn main() {
    //let seed: &[_] = &[1, 2, 3, 4, 5, 6 , 7 ,8, 9, 10, 11, 12,13 ,14,15,16];
    let seed: [u8; 32] = [
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
        0x1e, 0x1f,
    ];

    let mut rng: ChaChaRng = SeedableRng::from_seed(seed);

    for _ in 0..40 {
        println!("{}", rng.gen::<u32>());
    }
}

結果は下記になります。

2100034873
1780073945
1996733837
1229642936
1876440458
3429555900
1283312818
2451892952
3888915243
2871222434
1777274431
1686095930
3929375269
765720497
2690787266
205609800
826456088
3517376173
1633444115
659440559
4126388728
1549512161
318568684
1551185194
1829242994
1564274385
609780125
1006636644
1593221275
3461963230
2135566861
3445265713
3693998658
3583134375
4018841452
997363241
914301792
3082742343
815587571
3806560462

同一のseedを使用して自作のChaCha20の実装で乱数を発生させます。

#[test]
fn test_generate_rng() {
    let seed: Vec<u8> = vec![
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
        0x1e, 0x1f,
    ];

    let nonce: Vec<u8> = vec![
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ];

    let expected: Vec<u32> = vec![
        2100034873, 1780073945, 1996733837, 1229642936, 1876440458, 3429555900, 1283312818,
        2451892952, 3888915243, 2871222434, 1777274431, 1686095930, 3929375269, 765720497,
        2690787266, 205609800, 826456088, 3517376173, 1633444115, 659440559, 4126388728,
        1549512161, 318568684, 1551185194, 1829242994, 1564274385, 609780125, 1006636644,
        1593221275, 3461963230, 2135566861, 3445265713, 3693998658, 3583134375, 4018841452,
        997363241, 914301792, 3082742343, 815587571, 3806560462,
    ];

    let r = block_function(seed.clone(), 0, nonce.clone());
    for i in 0..16 {
        assert_eq!(expected[i], r[i]);
    }

    let r = block_function(seed.clone(), 1, nonce.clone());
    for i in 0..16 {
        assert_eq!(expected[i + 16], r[i]);
    }
}

結果が一致しました。

まとめ

なんとかRustでまとまったコーディングをすることができました。しかし、 RFCのセクション毎の実装をクリアすることに集中したため引数などのリス トをクローンしたりと及第点とは到底いえない状態です。

先ず、次の点を課題として認識しもう少し実装を磨こうと思います。

  • マクロ機能
  • ビット演算
  • モジュール構成

クレートとして公開するようなことはないでしょうが、公開の方法などを調 べて整えるまでできれば言語の学習としては一段落でしょうか?

大学の卒業研究で暗号学的ハッシュ関数MD5の後継であるMD6の高階差分解析 がテーマでした。卒業から4年程たったときに当時の研究室に連絡を入れ、 自分が作成した卒業論文を入手して続きを研究しようと考えました。その時 は転職や転居などがあり結局それは有耶無耶になりました。

現在も暗号とはそれほど関係ない業務ですが、FPGA等を触る機会があります。 そのような技術で当時の卒業研究のテーマをやったらどの程度のことができ たのかと考えることがあります。その度にあの時から勉強を続けていたら よかったなと後悔することもあります。

長期に渡る知見を蓄えた場合にどのような世界が見えるのか?いまから始め るのは遅い気もしますが、一つのテーマに腰を据え知見を蓄えその状態に到 達したいとそう思います。

この世界をサバイブするには

こんにちは、ヤマダです。
非常にご無沙汰、ご無沙汰でございますね…。
最近は全く東京にいません、展示会以降はお陰様で色々なお客様の元に訪問をしているため、専ら色々な土地を渡り歩いているため、東京にいると逆にそわそわしちゃいます。

少し前の話ですが、国内景気が後退局面傾向にあるニュースが流れていました。
この業界に限らず景気に左右されてしまう社会なので、こんな報道があると薄氷を歩くような気分です。
(個人的には、以前から徐々に景気が悪くなっていたように感ずるのですが…。)

そんな状況の中でもこと自動車という領域においては、「足を止めると息が止まる」、いくら企業として息切れをしていても決して手が止められない、手を止めたら最後数日であっという間に他社に追い抜かれてしまうという息切れしてしまうような切羽詰まった状況ですね。
一夜にして新鋭プレイヤーに追い抜かれていたり、かと思ったら一夜にして有名なプレイヤーが失落したりと業界全体がまさに激動、浦島太郎の心持ちを味わう人も多いかと思います。

社会においては雨降る悪条件の中、必ず決めなければいけない試合というのはままあるかと思うのですが、そんなぬかるみの中でも、むしろそのぬかるみを利用して鮮やかなシュートを決めちゃう人や企業もいますよね。
特にここで言う良いプレイを行う人間は、やはり海外勢が多いような気がしています。
日本企業は黙したまま泥に埋まっている、もしくは「泥から抜け出すにはどうすればよいか」という事を必死で考えており、その先の点を取る行動にまで考えが及んでいない所が多いんじゃないかなと思っています。

こういった中でも生き抜くには…とここ最近考えている生存戦略の話をしたいと思います。

iPXは半数以上が未経験者で構成されています、と言うと伝えた方全員にかなり驚かれます。
特に会社紹介なんかをすると、事業領域の広さに対して社員数の少なさと未経験者の多さに素直に感嘆される方が多いです。
しかも出身がかなりバラエティーに富んでいます、最近入社した人間だと作業療法士や科捜研の男、土木現場の監督していたと様々です。
ちなみに私もiPXに入社する前は工芸品を売っていました。

採用に関しては正直な所この売り手市場の現在経験者を取っている余裕すらないという実情もあるのですが、同じ遺伝子ばかりで構成されていると、突然環境が変異した場合対応できなくなるため、環境変化に順応できる組織体になるべく、異なる背景を持った人間を積極採用していると一個人としてはそう捉えています。
ただ同時に企業活動である以上、同じミッションを理解して協調していかないと、地力の高い組織になっていかないというのも事実です。
いかに個々人の能力の差別化を図りながら一体となっていくか、かなり実行の塩梅が難しいと感じるテーマですが、実はそういった命題は巷では溢れているのではないでしょうか。

「自分の軸はぶれず、かつ身につけた価値観(この文脈だと、バイアスと言った方が良いかもしれません)には固執せず、いかにキッパリと捨てられるか」
「いかに自分が変われるか、変わりながらいかに自分の変えない部分を作るか」
「いかに相手を尊重しながら自分の信念を伝えるか」
「どの観点で起こった事象を良しとするのか、どの観点で起こった事象を悪しとするのか」
「ルールに従いながら、いかに法則を塗り替えるか」
「いかに自分の利益を出しつつ、関わった全員が満足するか」

こういった一見矛盾をはらむ命題は、社会生活を送る上では避けて通れない壁として、大なり小なり立ちはだかっています。
それはフレキシブルな対応力なんていう平々凡々な言葉では語れないように思います。
恐らく正しい言葉として無いんじゃないかなと感じているのですが、あえて呼ぶとしたら矛盾を成立させる力、矛盾力をいかに付けるかが肝なのではないかと、最近は常々考えています。
矛盾を成立させることによる力は、片方向を成立させた推力よりもかなり大きく、かつ巡り巡って様々な物事に影響をもたらします。

でもそういった矛盾をはらむ力は、一度極端にまみれないと生まれません。
ということで、次回はその極端にフォーカスを当てた小話をしたいと思います…。