概要
かなりニッチな内容になりますが、
Lattigoという準同型暗号のライブラリの使用例を以前解説しました。
このLattigoには、CKKS形式の暗号の鍵交換
と呼ばれる機能が搭載されていますが、
使い方が制限される様な書き方になっていて少し困ったので、回避方法について調べてみました。
鍵交換
鍵交換とは、Aさんが復号可能な暗号を、
Bさんが復号可能な暗号に、暗号状態で変換する機能です。
鍵交換には、鍵交換を実行するための公開鍵である、鍵交換鍵が必要であり、
その鍵を前もって作っておく必要があります。
鍵交換鍵のプロトコル
鍵交換鍵の生成は、雑に書くと以下の様な流れになります。
- Aさんの暗号からBさんの暗号にするための鍵交換を実行したい
- Aさんの秘密鍵Aと、Bさんの公開鍵Bを使って、Aさんが鍵交換鍵(AtoB)を作成する
- Aさんがデータを暗号化して、暗号文Aを取得する
- AさんはCさんに鍵交換鍵(AtoB)と暗号文Aを送信する
- Cさんは鍵交換鍵(AtoB)と暗号文Aを使って、鍵交換を実行し、暗号文Bを取得する
- Cさんは暗号文BをBさんに送信する
- Bさんは自身の秘密鍵Bを使って暗号文Bを復号する
問題だった点
Lattigoの鍵交換鍵生成のための関数の定義を見てみると
GenSwitchingKey(skInput, skOutput *SecretKey) (newevakey *SwitchingKey)
となっており、
- Aさんの秘密鍵A
- Bさんの秘密鍵B
が必要な関数になっていました。
これだと先ほどのステップの、
Aさんの秘密鍵Aと、Bさんの公開鍵Bを使って、Aさんが鍵交換鍵(AtoB)を作成する
の時に、AさんはBさんの秘密鍵Bにアクセスすることになりますから、
これは実際問題としてやりたくないことです。
考えた解決策
GenSwitchingKey(skInput *SecretKey, pkOutput *PublicKey) (newevakey *SwitchingKey)
という様な関数を用意することが回避方法です。
こうすることで、先ほどの
- Aさんの秘密鍵Aと、Bさんの公開鍵Bを使って、Aさんが鍵交換鍵(AtoB)を作成する
ことが可能になります。
実際に作った解決策
上記の様な解決策に基づいてLattigo を少し変更しようと思ったのですが、
試行錯誤した挙句最終的に
GenSwitchingKeyExplicit(skInput *SecretKey,pkOutput *PublicKey, swk *SwitchingKey) (newevakey *SwitchingKey)
このような関数を作るのにとどまりました。
swkは鍵交換鍵のインスタンスですが、これを前もってBさんが生成しておいて、
Aさんに送っておくことが必要です。
こうすると、実際は鍵交換鍵の生成にはBさんの秘密鍵は実質的に使っていることに変わりはないのですが、
このswkをAさんに事前共有することは問題ないため、
Aさんが鍵交換鍵を生成する際に、Bさんの秘密鍵を取得する必要はない、
というもともと達成したかったことはクリアできています。
実装
実装は
こちらのコミットで行っています。
コードが汚いのは仕様です🙇
まとめ
今回は、Lattigoという準同型暗号のOSSライブラリを用いて鍵交換を実行する時の
関数をより実務的に処理するパッチについて備忘録的にまとめてみました。
興味のある方がもしいたらもっといい実装をやってみてください。
今回はこの辺で。