2019年度の未踏事業で「準同型暗号によるバーチャルセキュアプラットフォームの開発」というのをやっていました。その体験記というか感想というか、8ヶ月間何をやってたのかというのを晒したいと思います。例によってとりとめのない駄文なので読みにくいと思いますが、ゆるして
登場人物
- @nimdanaoto
- プロジェクトのリーダーで、言い出しっぺ。主に暗号理論や準同型暗号ライブラリの開発を担当。
- @VTb
- プロジェクトのメンバーで、言い出しっぺに最初に乗っかったやつ。主にプロセッサの実装と準同型暗号論理ゲート評価エンジンの実装を担当。
- @ushitora_anqou
- 筆者
はじまり
2月某日に @VTb からこんなDMが届きました。
@VTb「未踏で2人共同で出そうとしてるですけど、鮟鱇さんも興味ありませんか?テーマとしては準同型暗号上で動くセキュアなプロセッサエミュレーションです。」
@ushitora_anqou「とっても興味がありますが、それは私が噛んでも大丈夫なものですか?」
@VTb「今回のセキュアプロセッサを開発するに当たり、コンパイラや類するツールチェインの開発をする可能性があるので助けていただけると嬉しいです。あと、単純に強い人手がほしいのと、なんか楽しそうだからです」
「『なんか楽しそう』かぁ〜〜! そっかぁ〜〜!」と嬉しく思った記憶があります。能力をあてにされるよりも性格をあてにされるほうが嬉しいですよね。
このDMのあとオフラインで打ち合わせをしてその中身を把握し、正式にプロジェクトに参加することになりました。ちなみにこの時点で未踏の申込締切まで1週間程度しか無かったので急ピッチで申し込み書類などを書き上げて提出しました。その際の資料はここで公開しています。
無事に書類審査が通った後に二次審査(PMの前でプロジェクトについて話す)を受け、なんとか採択されることになりました。ここは特に面白いことが無かったので割愛。
LLVMバックエンドを書く
今回のプロジェクトの前半では、私はひたすらLLVMバックエンドを書いていました。LLVMバックエンドというのは、まぁ大雑把に言ってしまえばLLVM coreのコード生成を司っている部分で、抽象構文木(AST)からアセンブリを吐き出す部分を担当しています。このプロジェクトでは命令サイズを小さくする必要が有ったために、独自のISAを計3個も作成しました。この各ISA上でC言語を動かすために、LLVMを利用してCコンパイラを3回作成したわけです。
これがなかなかやっかいで、まずろくに資料がありません。LLVMのサイトを見れば “Writing an LLVM Backend” というドンピシャな文章があるように見えるんですが、これを読んでもバックエンドは書けません。というのも、チュートリアルのような書き方をされてはいないため、LLVM coreを何も知らない状況では読み解くのが難しく、全体として「分かっている人」を対象にしているような印象を受けました。他の資料としては、有名な「きつねさんでもわかるLLVM」にもLLVMバックエンドに関する記述がありますが、こちらも若干情報が古く、またLLVMバックエンドとしては限定された機能しか実装されていません。
最終的に一番参考にしたのはRISC-V用のLLVMバックエンド(とそれに関する資料)でした。RISC-Vバックエンド開発は(おそらく他のバックエンド開発を支援するという目的から)その開発資料を多く公開しています。例えばRISC-Vバックエンドを追加するイテレーティブなコードの編集をパッチの形式で公開しているほか、初めの方のパッチについてはドキュメントまで整備されています。
というわけで基本的な開発はRISC-Vバックエンドのパッチをひとつひとつ自分たちのISAに移植していく作業となりました。単純にコピペして名前を置換するだけですめば楽で良かったのですが、RISC-Vとは異なる部分も多かったため、そうもいかず大変でした。例えば条件分岐の際に直前の命令の演算結果を見て分岐するような命令(CMP+Jcc)を実装する際には、否応なくx86バックエンドを参考する必要があるわけですが、その規模の大きさと読みにくさに大変苦戦しました。
ただまぁ、いま振り返って見れば、かなり順調に進んだなぁという印象です。結局最後まで「コンパイラのせいで○○ができなかった」ということはありませんでした。
Iyokanの開発
1月くらいからは準同型暗号ゲートを実際に実行して結果を得るためのエンジンを書いていました。もともとは @VTb がIyokan-L2という名前で書いていたものを実装のアイデアだけはそのままにフルスクラッチし、より機能を追加したバージョンを作成しました。これを使うことで論理回路を、その論理ゲートを対応する準同型暗号のゲートに置き換えて実行することができ、それはつまり「暗号化された入力を暗号化されたまま実行して暗号化された結果を得る」というVSPの根幹のアイデアを可能にしています。
Iyokanが内部で実行している準同型暗号のゲートは、実際には外部のライブラリに処理を移譲しています。具体的には、CPUのみを用いて実行するときはTFHEpp、GPUも使用できる場合はcuFHEというライブラリを使用します。この二つのライブラリを透過的に、つまりIyokanのユーザーからは同じ操作感で使用できるように気を配りました。cuFHEにはなくTFHEppのみにある機能なども現時点では存在するため、cuFHEで処理したほうが速い場所はcuFHEで処理し、そうでない箇所は適宜cuFHE用のデータをTFHEpp用に変換した上でTFHEppに流し込む、といった機構も実装しました。
ところで現状のIyokanを、例えば手元にあるGPUのNVIDIA GTX 1660Tiなどで動作させると、テストに落ちます。面白いことに、NVIDIA V100という数値演算用のGPUで動作させるとテストは正常に終了します。もちろんIyokanの実装が何かしら間違っているということも大いに考えられるのですが、一方で数値演算用のGPUでないと計算誤りが発生するのではないかとも考えられます。このような特徴は、計算誤りにロバストな深層学習などではそれほど大きな問題になりませんが、暗号の演算では致命的です。普段このようなことが問題になる場所に出くわしたことが無かったため、この経験は新鮮でした。
小規模チーム開発
今回のプロジェクトで面白かったのは、メンバー各々がほか二人の作業内容を肩代わりできないことでした。例えば私はコンパイラ担当だったわけですが、他の二人はコンパイラの中身について詳細を知りません。同様に私は @VTb が作ったプロセッサの中身についてほとんど知らず、また @nimdanaoto が担当した暗号理論について私と @VTb はほとんど知りません。各々が自分の担当部分の仕事を完璧にこなし、各々の部分の結合に用いるインタフェース(ISAやライブラリAPIや論理回路のポート名)だけを統一していました。良く言えば疎結合で無駄がなく、悪く言えばバス係数がほぼ1で、誰かが倒れると後がありませんでした。
また開発方針が食い違うことも多く、Slackはよく殺伐としていました。議論で埒が明かないときにコードを叩きつける、という展開も何度かありました。お互いがお互いを尊敬しつつも、おかしいと思うことはズバズバ言うというスタンスで、最終的に成果が出たから良いものの、出ていなければ途中で空中分解してもおかしくない危うさがありました。ただこの雰囲気のおかげで良いものが作れたという自負も多少あります。
雑感
あんまりおもしろくない体験記になってしまいました。未踏期間、山あり谷ありだった気もするのですが、喉元すぎればなんとやらであんまり覚えていません。こんなことならaqccのときみたいに日記をつけておくんだったなぁと反省しています。ちなみに技術ログはつけてあるので、そのうち「自作ISAのためのLLVMバックエンドを書く薄い本」を出せればいいなぁと思ってリポジトリだけ作ってあります。
8ヶ月間かけて、自分は実装の人間なんだなぁというのを再認識した気がしています。手を動かすのがすきと言ってもいいかもしれません。理論を組み立てるよりも、それをどうコードに起こすかを考えるほうが好きみたいです。まぁ理論・実装ときれいに分けられるわけではないので結局両方をやる必要があるわけですが、そういう意味で今回のプロジェクトは @nimdanaoto に理論部分を全て投げられたので非常に楽でした。
あと未踏コミュニティについて多少Twitterなどで議論があるみたいですが、任意のコミュニティは閉鎖的になりがちというか、独自の文化を持つものなんじゃないかなぁと第三者的に考えています。真面目に考えていないのでこれ以上書きません。
最後に、VSPを担当していただいた首藤PMと、諸々のサポートをしていただいた未踏事務局の方々には大変お世話になりました。成果報告会のときには身内の謝辞を入れられなかったので、この場を借りて感謝申し上げます。ありがとうございました。