準同型暗号ライブラリの花形「Microsoft SEAL」をウェブ上で動かせるライブラリ「node-seal」爆誕！！

**@kenmaro**です。
普段は主に**秘密計算、準同型暗号などの記事について投稿しています**。
秘密計算に関連するまとめの記事に関しては以下をご覧ください。

> - [秘密計算エンジニアを始めて２年半が経った。](https://qiita.com/kenmaro/items/48059dd60f79e80f5ef8)
> - [秘密計算エンジニアを始めて3年が経った。](https://qiita.com/kenmaro/items/a1d90a074d552b7bf886)


## 忙しい人のために

https://github.com/morfix-io/node-seal

このライブラリ（今の所OSS）を使用することで、
ブラウザ上で準同型暗号を使用することができるようになります！！

また、このライブラリの開発者「morfix」が作っているモックアップのベータ版も公開されています。


https://morfix.io/sandbox

ご興味のある方は是非ご覧ください。



## 初めに

準同型暗号は、暗号化をした後も計算（足し算や掛け算）
を実行できる「次世代型暗号」
と呼ばれている暗号のことです。

準同型暗号の種類はいくつか存在するものの、
そのなかでも格子暗号は、量子コンピュータでも暗号を解読するアルゴリズムが見つかっていないことから、
「耐量子コンピュータ暗号」と呼ばれたりもしており、
とても面白い技術です。

もし準同型暗号ベースの秘密計算に興味のある方がいらっしゃいましたら、導入としてぜひ

https://qiita.com/kenmaro/items/a1d90a074d552b7bf886

こちらの記事をご覧いただければと思います。


また、技術の細部（理論、実装の最先端）を勉強してみたいと言う方は、

https://qiita.com/kenmaro/items/f2d4fb84833c308a4d29

是非こちらにチャレンジしていただきたいと思います。


## 準同型暗号のライブラリ群の現在

以上で述べた準同型暗号と呼ばれる技術ですが、
実装されているものとして幾つかのライブラリが挙げられます。
主にですが、C++での実装が多いです（GO言語も存在していたり、Rustのライブラリも最近は登場しています。）

この辺りは、網羅的にではないですが、

https://qiita.com/kenmaro/items/0654ad4d26e7a4dd919b

この記事にまとめておりますので、是非ご覧いただきたいです。


この中で、MicrosoftのSEALライブラリについて言及しています。

https://github.com/microsoft/SEAL

このライブラリが、現在準同型暗号ライブラリとしては一番広く使われています。
理由はいくつかあると思いますが、一番大きい理由として、

外部ライブラリへの依存関係がない（self-contained なOSSである）

ということが挙げられます。
他のライブラリがGMPやNTLといった外部ライブラリに依存しているのに対し、
SEALは全てMSのスクラッチのライブラリによって管理されているので、ビルドなどが行いやすいです。
もちろん、機能的にも優れている面もありますが、他の

https://github.com/homenc/HElib

などの有名ライブラリも機能としてはSEALよりも充実していたりします。


ただし、私の個人的な意見としては、初めて準同型暗号に触る人であれば、SEALからスタートした方が良いと考えています。



## モックアップを作る時の今までの弱点

ここでは、準同型暗号を用いたサービスの構成についてと、
なぜ導入が難しく複雑化しやすいか、（もしくは分かりにくいか）
ということについて解説します。

### 準同型暗号を用いたシステムのサービス構成

準同型暗号を用いたシステム（サービス）
を作ろうと考えた時、構成がわかりにくくなったり、セットアップが難しくなることがほとんどです。

理由は、

あくまでも鍵の管理はユーザのローカル環境である必要があるから

です。

準同型暗号を用いたシステムにおいて、このシステム固有の価値というものは、
サーバに暗号化されたデータを送信すると、何らかの処理を暗号状態で実行してくれて、
結果を暗号状態のまま返還してくれ、ユーザは結果を復号することで計算結果を得ることができる。
というシナリオにおいて、

サーバはユーザの入力値を復号する手立てがない
なぜなら、秘密鍵（暗号を復号することのできる鍵）はユーザのみが保持し、
サーバは公開鍵のみへのアクセスしかそもそもないからです。

したがって、サービス構成としては、
いくつかのサービスがユーザ側に存在し、いくつかのサービスがサーバ側に存在するような
ローカル側とサーバ側を跨った形のサービスとなります。

### サービスとしてのセットアップのやりやすさと、サービスとしての価値のジレンマ


ここで、先述したようなC++ベースのサービスをユーザ側にもデプロイすることになるわけですが、
いくつかの難しさが生じてきます。

- ユーザのローカル環境にシステムを整備する必要がある

これは、Dockerなどの技術を利用すれば、かなりハードルを下げることができます。
ただ、それでもユーザイクスペリエンスという観点からはかなり使いやすさが限定されます。

SaaSのような形でクラウド上で機能が完結すれば良いのですが、
それを考え始めた場合、ユーザのローカルにのみ存在していた秘密鍵は、ユーザの手を離れてクラウドで管理されることになります。
したがって、このサービスが提供するはずだった一番の価値である、

「ユーザのローカル環境に秘密鍵が存在し、計算環境からはアクセスする手立てすらない」
というストーリーを弱めてしまうことになるわけです。

これが準同型暗号型のサービス化を本気で考えた時の
「サービス化のジレンマ」

と呼べると考えています。


## SEALがJavascriptからコール可能に

ここで本題に入りますが、もし準同型暗号をJavascriptから呼べるような環境があれば、
鍵の生成や暗号化、復号などのコア関数を全てブラウザ上で行うことが可能になり、
ユーザサイドとして準備すべき環境はChromeなどのブラウザのみになります。

したがって、導入のしやすさとしては格段にハードルが下がるはずです。


これを可能にしたのが、今回紹介した

https://github.com/morfix-io/node-seal

このライブラリになります。
OSSとして、MITライセンスで現在公開されています。

このMorfixのデモを見てほしいのですが、
基本的な鍵の生成、暗号化、復号などはブラウザ上（ブラウザ上、しかもクライアント側）
で実行することができます。


ベースライブラリはSEALであり、SEALをウェブアセンブリでラップしているライブラリとなっています。
SEAL自体にもウェブアセンブリでコンパイルできるという記述があり、
筆者も簡単な暗号化などは実行したことがありますが、このように整備して簡単に呼べるようにライブラリ化してくれた、
というところは非常に価値のあることだと考えています。


私個人としては、このような方向に力を注げる実装屋の存在が非常に貴重であり、
我々もそのような活動をもっとしていきたいと考えています。


## 簡単にモックアップを作ってみました。
私たちも、node-seal を用い、クライアントサイドで暗号化、復号などを行う簡単なモックアップを実装してみました。

これらは、

@akakou さんと、　@kino-ma さんに

多大に貢献してもらっています。

![Screen Shot 2022-03-18 at 15.30.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519792/19fa0ae0-399d-263f-75eb-e02638743a1f.png)



BFV形式を用いて、ベクトルを暗号化し、それらを足し算し復号するという非常に単純なモックアップですが、
これをブラウザ上で行えるということは非常に素晴らしいことだと思います。
また、このモックアップはNextjsを用いて作られており、簡単にUIもきれいにしたり、
実際のユーザ体験を加味してよりよいものに拡張しやすいものとなっています。

プログラムの例ですが、
NextJSを用いて、ブラウザでユーザが鍵を生成し、それを共通鍵型の暗号で暗号化し、
ローカルストレージに保存しているようなコードは

```javascript
import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useMutation,
  MutationTuple,
  MutationResult,
} from "@apollo/client";
import { useState } from "react";
import {
  AddUserDocument,
  AddUserMutation,
} from "../../graphql/dist/generated-client";
import { initParams, serializePub } from "../../libs/ckks";
import { genAESKey, exportKey, encrypt } from "easy-web-crypto";
import { saveUser } from "../../libs/auth";

interface StatusProps {
  pubkey: string;
  mutation: MutationResult<AddUserMutation>;
}


  const onClick = async (e) => {
    // calculate new key
    const params = await initParams();
    const newPubkey = serializePub(params.pub);
    const privkey = params.priv.secretKey.saveArray();
    const password = await genAESKey();
    const exportedPassword = await exportKey(password);
    // convert to integer array, then spread them into an number[]
    // (f.apply(_, [x,y]) is equal to f(x, y))
    const encodedPassword = String.fromCharCode.apply(
      null,
      new Uint8Array(exportedPassword)
    );

    const encryptedPrivkey = await encrypt(password, privkey);
    const encryptedJSONPrivkey = JSON.stringify(encryptedPrivkey);

    localStorage.setItem("password", encodedPassword);

    const { data } = await addUser({
      variables: {
        name: userName,
        pubkey: newPubkey,
        encryptedPrivkey: encryptedJSONPrivkey,
      },
    });

    if (error) {
      alert(`Error occured while registering: ${error}`);
      return;
    }

    if (!loading && data) {
      saveUser(data.addUser);
      setPubkey(newPubkey);
    }
  };

```

みたいな感じで実行しています。

この点で、やはりJavascriptで実行できるように整備されているということはすごい価値を持つものだなと感じているところです。

例えば、私が最近いくつか記事を書いた、TFHEppなどのプログラマブルブートストラップなどに対しても、
このようにwebassemblyを用いてラップすることにも取り組んでみたいと考えています。
もし興味がある人がいらっしゃいましたら、コメントしていただくか、ツイッターなどにご連絡いただければと思います。



## まとめ

以上、簡単ではありましたが、準同型暗号の花形ライブラリ
「Microsoft SEAL」をウェブ上で実行できるライブラリ

https://github.com/morfix-io/node-seal

について紹介をしました。

また、このライブラリの開発者「morfix」が作っているモックアップのベータ版も公開されていますので是非ご覧ください。


https://morfix.io/sandbox


このようにユーザ目線での領域をひたすら伸ばそうとする取り組みは素晴らしいと思います。

私もこれらのライブラリを用いてアプリケーションを伸ばす方向に力を使ったり、
このようなライブラリをサポートしたり、これらのライブラリを作成するような側に回ったり、

もっといろいろな方向で貢献できればと思っています。


今回はこの辺で。


@kenmaro