目次
- はじめに {#introduction}
- 完全準同型暗号(FHE)とは {#what-is-fully-homomorphic-encryption-fhe}
- FHE の背後にある数学的概念 {#mathematical-concepts-behind-fhe}
- FHE の背後にある計算機科学の概念 {#computer-science-concepts-behind-fhe}
- 数学的基礎 {#mathematical-foundations}
- CKKS の実行トレース例 {#execution-trace-example-of-ckks}
- Rust の例 {#rust-example}
- 結論 {#conclusion}
- 参考文献 {#references}
はじめに
データのプライバシーとセキュリティが最重要の課題となった現在、復号せずに暗号化データのまま計算を行えることは、現代暗号における最大級のブレークスルーです。完全準同型暗号(FHE)はまさにその能力を提供します。基となる情報を完全に秘匿したまま、暗号文に対して任意の計算を施すことを可能にする革命的な手法です。
たとえば、個人の機微な財務データをクラウドに送り、複雑な分析を依頼しても、サービス提供者に実際の数値を一切見せずに済むとしたらどうでしょう。あるいは、患者情報を露わにすることなく、暗号化された医療記録を使って機械学習モデルを学習させることができたらどうでしょう。かつては不可能と考えられていたこれらのシナリオは、FHE によって現実味を帯びています。
本稿は、完全準同型暗号の数学的基礎、実装、そして実世界での応用を俯瞰的に紹介します。BFV、BGV、CKKS、TFHE といった先進的な暗号方式に触れ、それぞれがどのように計算需要の違いに応えつつ、データの完全なプライバシーを維持するのかを見ていきます。
暗号研究者、プライバシー保護技術に関心のあるソフトウェア開発者、あるいは安全な計算の未来に好奇心を持つ読者にとって、本稿は理論と実践の両面から、暗号分野で最も期待されるフロンティアのひとつを体系的に理解する助けとなるでしょう。
完全準同型暗号(FHE)とは
FHE の革新性を理解するため、まずその基本命題から始めましょう。平たく言えば、FHE は元のデータを見ることなく、暗号化データに対して計算を行える特殊な暗号方式です。
通常、データを暗号化すると、加算・乗算・分析などの処理をするには一度復号する必要があります。ところが FHE では次のようにできます。
- データを暗号化する
- それを第三者(たとえばクラウドサーバ)に渡す
- 第三者は暗号化されたままのデータに対して計算を実行できる
- 最後に自分で結果を復号すると、元の平文に対して同じ計算をしたときと同一の結果が得られる
つまり、処理の全過程を通じてデータは秘匿されたままなのです。
たとえば 5 と 3 を暗号化して送ったとします。クラウドは復号せずにそれらを加算し、暗号化された結果を返します。こちらで復号すると 8 が得られます。この間、クラウドは 5 や 3 といった値を知ることなく、5 + 3 を正しく計算できたわけです。
この「一見すると不可能」な能力は、多様な産業における変革の扉を開きます。以下では、FHE が今日すでに現実の課題解決に役立っている最も説得力のあるユースケースを見ていきます。
実用的なユースケース
- プライバシー保護型クラウド計算:利用者は医療記録や財務情報などの機微データを、実内容をクラウド事業者に明かすことなく、保管・処理できます。
- セキュア機械学習(暗号化 AI):AI モデルの学習や推論を暗号化データ上で実行可能。たとえば病院は、患者の個人情報を明かさずに疾病リスク評価を行えます。
- 金融:銀行は、実際の残高や取引を見ずに、暗号化された顧客データでリスク分析や不正検知を実施できます。
- 政府・防衛:機密情報を外部と安全に共有・分析できます。
- 企業間データ連携:生データを開示せず、(たとえば顧客行動分析などで)相互に協調可能です。
FHE は数学的に高度で計算負荷も大きく、通常の処理より大幅に遅くなります。しかし、Microsoft SEAL [1]、IBM HElib [2]、Google の FHE ライブラリ [3][4]、Zama Concrete [5] などの進歩により、とくに限定的な計算や小規模データセットでは実用性が高まりつつあります。
FHE の変革的な可能性をより具体的に示すため、すでに現実のプライバシー課題を解決し始めている 2 つのシナリオを見てみましょう。
医療 — 安全な医療データ解析
現代医療の課題のひとつは、病院やクリニックが患者データ(MRI 画像や遺伝情報など)を解析して疾患パターンを見つけたり治療を改善したい一方で、HIPAA や GDPR のような法規制により、このデータを自由に共有できないことです。
FHE がどう助けるか:
- 各医療機関は、患者データを FHE で暗号化してから、中央のクラウドや研究サーバへアップロードします。
- クラウド上の研究者や AI システムが、例えば次のような計算を行います:
- 2.1. 「この遺伝子を持つ患者の何%が糖尿病を発症するか?」
- 2.2. 「早期がんを検知する AI モデルを学習せよ」
- これらすべての計算は暗号化データのまま実行されます。
その後、病院側が最終結果を復号し、有用な統計や学習済みモデルを得ますが、個々人の医療情報は一切露わになりません。
画期的な利点:機微な医療記録は可読な形で院外に出ない一方、世界的な研究協調が可能になり、患者のプライバシーを守りながら医療の進歩を加速できます。
銀行 — プライバシー保護型クレジットスコアリング
金融分野でも同様のジレンマがあります。銀行は、収入・消費傾向・負債などの包括的データを使ってクレジットスコアを算出したい一方で、顧客はすべての私的情報を外部のスコアリングサービスやクラウドに晒すことを嫌います。
FHE がどう助けるか:
- 顧客の財務データを暗号化してからスコアリングサービスに送ります。
- スコアリングサービスは、(合計・平均・リスク式などの)アルゴリズムを暗号化データ上で実行します。
- 結果(クレジットスコア)は暗号化されたまま銀行へ返送されます。
- 銀行はローカルで結果を復号し、スコアのみを得ます。スコアリング事業者は生の数値を一切見ません。
結果:スコアリングの正確性を維持しつつ、機微な財務データはどの関係者にも露見しないという、関係者すべてにとっての Win-Win が実現します。
これらはほんの端緒にすぎません。応用分野は次のように広がっています。
- IoT デバイス:スマートセンサーが暗号化された計測値(家庭の電力メータなど)を送信し、行動パターンを露見させずに分析可能
- クラウドストレージ:暗号化されたデータベースに対する「検索」や「フィルタ」を提供
- 選挙:個々の投票内容を晒すことなく集計を可能にする暗号化開票
実用面を確認したところで、「FHE は実際どう動くのか?」という本質に踏み込みましょう。そのためには、この魔法のような性質を支える数学的原理を理解する必要があります。
FHE の背後にある数学的概念
FHE の核心には巧妙な数学的洞察があります。従来の暗号では、暗号化によって得られる暗号文はランダムな数の集まりのようで、復号するまで役に立ちません。ところが FHE では、暗号文の構造を特別に設計し、暗号文に対する演算が復号後の意味ある結果に対応するようにします。
言い換えると:
暗号文上の演算 = 隠された平文に対する実際の演算
したがって、
- $5$ を暗号化して $E(5)$
- $3$ を暗号化して $E(3)$
としておけば、
- $E(5)+E(3)=E(8)$
- $E(5) \times E(3)=E(15)$
復号すると、初めから終わりまで暗号化されたままだったにもかかわらず、正しい結果が得られます。
この特性は、FHE の暗号方式が慎重に設計された数学構造に基づくために実現します。概念的に、どの FHE 方式も次の 3 ステップを含みます。
- 暗号化:各数値を秘密鍵を用いて多項式(数式)へと変換します。元の値が推測できないように攪拌(スクランブル)されます。
- 暗号化データ上の計算:加算や乗算といった演算を、多項式上の演算に写像します。復号後に、平文上で得られるべき正しい結果に対応するように設計されています。
- 復号:秘密鍵で「攪拌」を解き、計算結果の平文を取り出します。
「ホモモルフィック(homomorphic)」という語は、この本質的な数学的性質を表しています。
なぜ「ホモモルフィック(準同型)」と呼ぶのか? homomorphic は「同じ構造を保つ」という意味です。 ここでは、暗号文上の演算($+$ や $\times$)が、平文上の演算と同じ構造で振る舞うことを指します。
| 演算の種類 | 意味 | 例 |
|---|---|---|
| 加法準同型 | 暗号化データを加算で合成できる | $E(5) + E(3) = E(8)$ |
| 乗法準同型 | 暗号化データを乗算できる | $E(2) \times E(4) = E(8)$ |
| 完全(Fully)準同型 | 加算と乗算の両方が可能 | $\rightarrow$ 暗号化データ上で任意の関数を計算可能 |
この区別は、数十年にわたる研究の結晶です。長らく暗号方式は、加算か乗算のどちらか一方しか安定にサポートできず、用途が大きく制限されていました。転機は 2009 年、Craig Gentry [6] がスタンフォード大学の博士論文で初の完全準同型暗号を構成したことです。
最大の課題は次の点でした。
- 各演算は暗号文に「ノイズ」を蓄積する
- ノイズが大きくなりすぎると復号不能になる
- Gentry の鍵となる洞察は、暗号文のノイズを定期的に**「リフレッシュ」**する(ブートストラップ)こと
このブレークスルーにより FHE は理論的に可能となり、プライバシーを保った計算への道が開かれました。
Gentry の基礎理論の上に、現代の FHE ライブラリは数々の最適化を積み上げ、実用に耐える形へと近づいています。
- 後述の格子(lattice)暗号に基づく設計
- 実数を近似で扱うことによる高速化
- 並列化による性能向上
理論と実装の橋渡しを理解するため、次に計算機科学的な原理を見ていきます。
FHE の背後にある計算機科学の概念
数学的直観を押さえたところで、FHE を形式的に定義し、計算上の課題に目を向けます。形式的には、FHE は次のように定義できます。
FHE は $(KeyGen, Enc, Dec, Eval)$ からなる暗号方式であって、任意の効率的に計算可能な関数 $f$ について $Dec(sk, , Eval(pk, f, , Enc(pk, x))) = f(x)$ を満たす。
すなわち、暗号文 $c_i = Enc(pk, x_i)$ が与えられたとき、復号することなく $c_f = Eval(pk, f, c_1, \ldots, c_n)$ を計算でき、$Dec(sk, c_f) = f(x_1, \ldots, x_n)$ が成り立ちます。
このとき、FHE は次の間の準同型写像を提供します。
- 平文ドメイン(整数・実数・ベクトルなど)
- 暗号文ドメイン(通常は剰余環上の多項式)
実用的な多くの FHE 方式は LWE(Learning With Errors;誤りつき学習) [7] またはその環版である Ring-LWE(環上 LWE) [8] に基づきます。
鍵となる考え方:
暗号文は、以下のようなノイズ付きの線形(または多項式)方程式として表現されます。 $c = \bigl(a,, b = \langle a, s \rangle + m + e\bigr) \bmod q$
ここで、
- $s$:秘密鍵(ベクトルまたは多項式)
- $m$:平文(小さな法 $t$ に埋め込む)
- $e$:ノイズ(小さい乱数誤差)
- $q$:暗号文の法(モジュラス)
復号では $m \approx b - \langle a, s \rangle \bmod q$ を回復します。$e$ が十分小さい限り、$m$ を取り出せます。しかし準同型演算を重ねるとノイズは増大するため、ブートストラップ(ノイズのリフレッシュ)が必要になります。
暗号文がサポートする基本演算は 2 つです。
加算:成分ごとに和をとる:$(a_1,b_1) + (a_2,b_2) = (a_1+a_2,, b_1+b_2)$。平文の加算に対応し、ノイズはわずかに増えます。
乗算:多項式として乗算。ノイズは急増(概ね乗法的)するため、次が重要になります。
- モジュラス切替(modulus switching):法 $q$ を段階的に小さくしてノイズの相対量を抑える
- 再線形化(relinearization):次数が上がった暗号文を既定の次元へ戻す
ノイズ管理こそが FHE エンジニアリングの中核課題です。
**ブートストラップ(Gentry の洞察)**は、復号回路そのものを暗号文上で評価することです。
- 秘密鍵を「自分自身で暗号化」して用意する
- ノイズが大きくなったら、暗号化された鍵を用いて復号関数 $Dec$ を $Eval$ で実行し、暗号文をリフレッシュする
- 平文はそのままに、ノイズだけを減らした新しい暗号文を得る
ブートストラップは高価(ネイティブ演算より桁違いに遅い)ですが、「完全」準同型性には不可欠です。近年は、暗号化計算のための**コンパイラと中間表現(IR)**も活発に研究されています。
概念図:
高レベルプログラム(Python, C++, ML モデル)
↓
同型計算用 IR(加算·乗算·回転、剰余演算)
↓
回路表現(ブール回路 or 算術回路)
↓
暗号文演算(Eval によるゲート評価)
コンパイラは次を行います。
- 回路最適化(ブートストラップ不要にするため、乗算深さを最小化)
- パラメータ選択(安全性と精度のバランスを取る $q, t, N$ の選定)
- ノイズ追跡(記号的解析による誤差管理)
代表的な FHE 方式
| スキーム | 種別 | 特徴 | 典型用途 |
|---|---|---|---|
| BFV [9] | 正確な整数演算 | 剰余算(モジュラ) | データベース照会 |
| BGV [10] | 正確な整数演算 | 法の切替 | 汎用 |
| CKKS [11] | 近似実数演算(実数・浮動小数) | スケーリング符号化 | ML 推論 |
| TFHE [12] | ビットレベルのブール論理 | 高速ブートストラップ | 論理回路 |
コンパイラ開発の視点では、FHE とは高級言語のコードを代数回路へ写像することに他なりません。制約は以下の通りです。
- 加算と乗算のみ:分岐や任意アクセスは不可
- ノイズ追跡:浮動小数の丸め誤差管理に似た考え方
- 回路深さの最小化:ブートストラップの回避・削減
- ベクトル化パッキング(暗号文内 SIMD):多項式の CRT 表現で複数スロットを一括処理
FHE コンパイラはしばしば、次のツールに似ています。
- ハードウェア合成ツール(Verilog → 論理ゲート)
- MPC(Secure Multi-Party Computation)コンパイラ(ただし代数ノイズモデルを持つ)
現在の性能感:
- 基本算術:ミリ秒級
- ブートストラップ:おおよそ 10–100 ms(改善が続く)
- 平文計算に比べ $10^4$~$10^6$ 倍遅いことが多いが、改善傾向
これらの枠組みは、暗号とシステムの両面の専門性を要する理由を示します。
| 観点 | 従来システム | FHE における対応物 |
|---|---|---|
| データ型 | 整数・実数(平文) | 剰余環上の暗号文 |
| 演算 | ALU 演算($+, \times$) | 同型 Eval |
| 精度の管理 | 浮動小数の丸め | ノイズ追跡 |
| 最適化目標 | 性能 | 回路深さ・ノイズ最小化 |
| メモリ配置 | ベクトル化 | 暗号文内のバッチ(SIMD スロット) |
| IR / バックエンド | LLVM, MLIR | FHE 向け DSL / フレームワーク |
次に、これらの実装を支える数学的基盤を見ていきます。
数学的基礎
現代の FHE の安全性は格子暗号に由来します。これは高次元空間の幾何学的構造(ラティス)を扱う数学分野です。基本から見ていきます。
格子の定義:格子 $\mathcal{L} \subset \mathbb{R}^n$ は基底ベクトルの整数係数線形結合全体: $\mathcal{L} = { a_1\mathbf{v_1} + a_2\mathbf{v_2} + \dots + a_k\mathbf{v_k} \mid a_i \in \mathbb{Z} }$。高次元の格子状の点集合とみなせます。
この幾何学的基盤の上に、ほとんどの FHE を支えるLWE(Learning With Errors;誤りつき学習)問題があります。
多数のサンプル $(a_i, , b_i = \langle a_i, s \rangle + e_i \bmod q)$ が与えられ、$a_i \in \mathbb{Z}_q^n$ はランダム、$e_i$ は小さな誤差、$s \in \mathbb{Z}_q^n$ は秘密ベクトルのとき、$s$ を求めるのは計算困難(量子耐性あり)とされます。
この困難性により、暗号文が平文情報を漏洩しないことが保証されます。
しかし、素の LWE だけでは実用には重いことが多いため、効率化のために多項式環へ一般化します。
$R_q = \mathbb{Z}_q[x]/(x^N + 1)$ とします。
すなわち、大きな整数 $q$ と巡回多項式 $(x^N + 1)$ での剰余をとる多項式環です。係数は法 $q$ で、次数は $(x^N + 1)$ による剰余で折り返します。
- $N$:環の次数(2 の冪。例:$2^{14} = 16384$)
- $q$:暗号文の法(大きな素数または合成数)
この枠組みの安全性は、Ring-LWE(環上 LWE)に基づき、LWE と同様の困難性を保ちながら効率を高めます。
この数学構造に基づき、暗号化と復号は次のように動作します。
暗号化
秘密鍵 $s \in R_q$、平文 $m \in R_t$($t \ll q$)に対し: $$c = (c_0, c_1) = (b, a) = (a \cdot s + m + e,; -a)$$
ここで:
- $a \leftarrow R_q$ はランダム
- $e \leftarrow \text{小さなノイズ}$
- $m$ は $q$ に合わせてスケーリングして埋め込む
復号
$$m’ = (c_0 + c_1 \cdot s) \bmod q$$
ノイズ $e$ が小さければ、丸めにより $m \bmod t$ を回復できます。
準同型演算
加算:$(c_0, c_1) + (c_0’, c_1’) = (c_0 + c_0’, ; c_1 + c_1’)$。平文では $(m + m’)$ に対応し、ノイズは線形に増加。
乗算: $$(c_0, c_1) \cdot (c_0’, c_1’) = (c_0 c_0’, ; c_0 c_1’ + c_1 c_0’, ; c_1 c_1’)$$
これは3 成分の暗号文($s$ の次数が 2)を生みます。
2 成分に戻すために、事前計算した鍵スイッチング鍵を用いて再線形化を行います。
法とスケーリング
FHE は大きな法 $q$(例:$2^{200}$~$2^{600}$)で動作します。各演算でノイズ $e$ は増え、$e$ を $q$ に対して十分小さく保つ必要があります。
制御手段:
- モジュラス切替:演算の途中で $q$ を縮小し、相対ノイズを抑える
- 再スケール(CKKS):近似実数計算では、スケーリング係数を割って精度を管理
CKKS:実数の近似演算
ML や信号処理では整数の厳密性だけでは足りません。
CKKS は実数を大きなスケール $\Delta$ で整数化して符号化し、近似演算を可能にします。
符号化:$m \mapsto \lfloor \Delta \cdot m \rceil \bmod q$(例:$\Delta = 2^{40}$)。
乗算のたびにスケールが増えるため、再スケールで $\Delta$ を割って整えます: $c’ = \text{Rescale}(c_1 \cdot c_2, \Delta)$。
復号後は真値の近似が得られ、誤差はノイズによって上界づけられます。
ノイズが $q/2$ に近づくと復号不能になります。 ブートストラップは復号回路を暗号化のまま評価することでノイズをリセットします。暗号化された秘密鍵とノイズの大きい暗号文を使って、同じ平文を持つ新鮮な暗号文を生成します。ここでは剰余演算や丸めの多項式評価が必要で、計算的に最も難所です。
パラメータ選定のバランス:
- 安全性:Ring-LWE の困難性に基づく(例:128 ビット相当)
- 正確性:ノイズ $< q/2$ を維持
- 精度:スケール $\Delta$ により制御
- 性能:$N$ や $q$ が大きいほど遅い
典型的な CKKS 構成:
| パラメータ | 値 | 意味 |
|---|---|---|
| $N$ | $2^{14} = 16384$ | 多項式次数 |
| $q$ | $\sim 2^{400}$ | 暗号文の法 |
| $\Delta$ | $2^{40}$ | スケーリング係数 |
| Security | 128 bits | 標準的強度 |
| Encoding | 複素数パッキング(SIMD) | 約 8192 スロット |
中国剰余定理(CRT) [13] により、複数の平文を1 本の暗号文にパックできます。暗号文上の演算はスロットごと(要素ごと)に作用し、暗号化された SIMD のように機能します。
数学的には:$R_t / (x^N+1) \cong \prod_{i=1}^{N/2} \mathbb{C}$。 各複素スロットに 1 値を格納でき、大幅な並列性を得ます。
これらを階層構造として整理すると:
| 層 | 概念 | 形式構造 |
|---|---|---|
| 安全性の基盤 | 難解な格子問題 | (環上)LWE |
| 代数構造 | 多項式環 $\bmod ( q, x^N+1 )$ | $R_q$ |
| 暗号化 | ノイズ付き線形写像 | $b = a \cdot s + m + e$ |
| 準同型性 | 環演算 | $R_q$ 上の加算・乗算 |
| ノイズ制御 | モジュラス切替・ブートストラップ | $e \ll q/2$ を維持 |
| 符号化 | 整数/実数のパッキング | CRT + スケーリング |
| 評価 | 算術回路の実行 | Add, Mul, Rotate, Rescale |
次に、これらが実際の計算でどのように働くか、CKKS の完全な計算例を追って確認します。
CKKS の実行トレース例
理論と実装の溝を埋めるため、CKKS による $(x+1)^2$ の計算を段階的に追跡します。これは同型評価の要点を示すシンプルな例です。
パラメータ(現実的かつ説明用)
- 環:$R_q=\mathbb{Z}_q[x]/(x^N+1)$、$N=2^{14}=16384$
- 法のチェイン(上位 → 下位):$\mathcal{Q}=[q_0,q_1,q_2]=[\approx 2^{40}, \approx 2^{40}, \approx 2^{40}]$
- 初期スケール:$\Delta = 2^{40}$(乗算と再スケール後に $\approx 2^{40}$ に戻す)
- 目標セキュリティ:およそ 128 ビット($N, q_i$ の桁感に対応)
- 符号化:CKKS 複素スロット;ここでは 実数 1 スロットのみ使用
- 例:$x=1.2345$ → 真値 $(x+1)^2 = 4.99299025$
注 1:**レベル($L$)**は、法チェインに残る素数の段数を示します。開始時は $L=2$($q_0 q_1 q_2$ を使用)。
注 2:「ノイズバジェット」は復号失敗までの「残りビット数」に相当する指標です。以下の値は実装依存であり、あくまで目安です。
ステップごとのトレース
| Step | 操作 | 入出力(暗号文/平文) | 理想値 | スケール | レベル | ノイズの挙動 |
|---|---|---|---|---|---|---|
| 0 | 符号化 $x$ | $- \rightarrow p_x$ | $x$ | $\Delta \approx 2^{40}$ | L2 | エンコーダが $x$ を多項式へ写像;丸め誤差は $\ll 1/\Delta$。 |
| 0′ | 符号化 $1$ | $- \rightarrow p_1$ | $1$ | $\Delta$ | L2 | 後で加算できるよう同一スケール。 |
| 1 | 暗号化 | $(p_x \to c_x)$, $(p_1 \to c_1)$ | $(x,;1)$ | $\Delta$ | L2 | 各暗号文に RLWE ノイズ($\varepsilon \sim \mathcal{O}(\sigma)$)。 |
| 2 | 加算 | $c_a = c_x + c_1$ | $x+1$ | $\Delta$ | L2 | ノイズは線形に増加;バジェットがわずかに減少。 |
| 3 | 自乗 | $c_s = c_a \times c_a$ | $(x+1)^2$ | $\Delta^2 \approx 2^{80}$ | L2 → L2(直後) | ノイズが乗法的に増加し次数も上昇;再線形化で 2 成分に戻し、さらにノイズが増える。 |
| 4 | 再スケール | $c_r = \text{Rescale}(c_s)$ | $(x+1)^2$ | $\Delta^2 / q_2 \approx 2^{40}$ | L1($q_2$ 低下) | $q_2$ で割ることで大きさ(と実効ノイズ)を抑制;スケールを $\Delta$ 近辺に復元。 |
| 5 | 復号 | $c_r \to p_r$ | $(x+1)^2 + \text{err}$ | $\Delta$ | L1 | 総誤差が $\Delta/2$ 未満なら正しく回復。 |
| 6 | 復号後の復元 | $p_r \to \hat{y}$ | $\hat{y} \approx 4.99299025$ | - | - | 最終的な丸め。誤差は符号化+CKKS 近似+演算ノイズで決まる。 |
ノイズバジェットの例(概略):開始時 L2 で約 110–120 bit → 加算後 ~108 bit → 乗算+再線形化後 ~60–70 bit → 再スケール後 ~50–60 bit(さらに数演算可能)。
数値のイメージ(概略)
- 加算後:値 $\approx 2.2345$、スケール $2^{40}$
- 自乗(再スケール前):値 $\approx 4.99299025$、スケール $2^{80}$
- $q_2 \approx 2^{40}$ で再スケール:値 $\approx 4.99299025$、スケール $2^{40}$ に復帰、レベルは L1
- 復号/復元:$4.99299025 \pm 10^{-9}$ 程度($\Delta$, $N$, パラメータに依存)
要点:
- CKKS のスケール規律:オペランドのスケールを整合させる。乗算後は再スケールして作業スケールへ戻し、チェインの素数を 1 つ落とす
- 深さ管理:本回路の乗算深さは 1(自乗のみ)なので再スケール 1 回で十分;ブートストラップ不要
- 再線形化:乗算後に暗号文サイズを固定に戻す(性能・ノイズの観点)
- パラメータ選定:$\Delta$ を 40bit 素数付近に取り、$\Delta^2/q \approx \Delta$ を満たす。最悪ケースの深さに合わせてチェイン長を決める
$(x+1)^2$ の最小 IR(CKKS 風)
c_x = Enc(x, scale=2^40, level=L2)
c_one = Enc(1, scale=2^40, level=L2)
c_a = Add(c_x, c_one) // スケール 2^40, L2
c_s = Mul(c_a, c_a) // スケール ~2^80, L2
c_s = Relin(c_s) // 同スケール, L2
c_r = Rescale(c_s) // スケール ~2^40, L1
y_hat = Dec(c_r) // ≈ (x+1)^2
さらに乗算が 1 回必要なら L1 が残っているので可能(その後再スケールで L0)。より深い回路ではチェインを延長し、尽きたらブートストラップでリフレッシュします。
実際の CKKS の数式操作を追ったところで、次にコードとしてどう書けるのかを見ていきます。現代の FHE ライブラリは多くの複雑さを抽象化し、馴染みのあるプログラミングパターンで暗号化データを扱えるようにしています。
Rust の例
同じ $(x+1)^2$ を、ハイパフォーマンスな Rust 製 FHE ライブラリ TFHE-rs を用いて実装してみます。先ほどの数学的操作が、いかに簡潔なコードに落ちるかが分かります。
TFHE-rs は 8~128bit の暗号化整数をサポートし、演算子オーバーロードにより直感的に記述できます。再線形化や鍵スイッチングは内部で自動処理されます。
Cargo.toml
[package]
name = "fhe_test"
version = "0.1.0"
edition = "2024"
[dependencies]
tfhe = { version = "~1.4.1", features = ["integer"]}
[profile.release]
lto = "fat"
Gist
use tfhe::{ConfigBuilder, FheUint64, generate_keys, prelude::*, set_server_key};
fn main() -> tfhe::Result<()> {
let config = ConfigBuilder::default().build();
// 2) クライアント鍵生成
let (client_key, server_key) = generate_keys(config);
// 3) サーバ鍵を「アップロード」(実運用ではサーバ側が保持)
set_server_key(server_key);
// 平文の x:
let x_clear: u64 = 1_234_567;
// 4) x と定数 1 を暗号化
let x: FheUint64 = FheUint64::try_encrypt(x_clear, &client_key)?;
let one: FheUint64 = FheUint64::try_encrypt(1u64, &client_key)?;
// 5) 同型計算: (x + 1)^2
// 演算子オーバーロードにより、平文コードのように書ける
let y = (&x + &one) * (&x + &one);
// 6) 復号
let y_clear: u64 = y.decrypt(&client_key);
// 平文計算での整合性チェック
let expected = (x_clear + 1).wrapping_mul(x_clear + 1);
assert_eq!(y_clear, expected);
Ok(())
}
注記:
- 例では
FheUint64を用いています。必要に応じてFheIntXX/FheUintXXに変更可能です。 - TFHE-rs は暗号化値に対して
+ - * / % << >> & | ^や比較を提供します。定数は平文でも暗号化でも使用できます。

コマンド:
RUSTFLAGS="-C target-cpu=native" cargo run --release
10 回の連続実行における性能結果:
===============================================================================
FHE 実験結果 - 10 回実行
===============================================================================
Run | 鍵生成 | 暗号化 | 計算 | 復号 | 合計
-----+--------------+------------+------------+------------+-------------
1 | 655ms | 5ms | 5.43s | 0ms | 6.09s
2 | 445ms | 5ms | 5.49s | 0ms | 5.95s
3 | 469ms | 5ms | 5.37s | 0ms | 5.85s
4 | 427ms | 5ms | 5.36s | 0ms | 5.79s
5 | 469ms | 5ms | 5.39s | 0ms | 5.87s
6 | 447ms | 5ms | 5.50s | 0ms | 5.96s
7 | 470ms | 5ms | 5.44s | 0ms | 5.92s
8 | 434ms | 5ms | 5.56s | 0ms | 6.01s
9 | 451ms | 5ms | 5.48s | 0ms | 5.94s
10 | 435ms | 5ms | 5.42s | 0ms | 5.87s
-----+--------------+------------+------------+------------+-------------
AVG | 470ms | 5ms | 5.44s | 0ms | 5.93s
===============================================================================
このコード例から、環上多項式・ノイズ管理・ブートストラップといった複雑な数学が、どれほど直感的な API に抽象化されているかが分かります。ツールの成熟に伴い、FHE 理論と実践の溝は着実に埋まりつつあります。
結論
本稿の終わりに、完全準同型暗号(FHE)が示す驚くべき歩みを振り返りましょう。2009 年の Craig Gentry による理論的突破から、今日の TFHE-rs、Microsoft SEAL、Zama Concrete などの実装まで、FHE は抽象的な数学概念から現実に適用可能な技術へと進化しました。
BFV・BGV・CKKS・TFHE といった各方式は、それぞれに強みを持ちます。BFV と BGV は厳密な整数演算に強く、正確な計算が必要な用途に適します。CKKS は実数の近似演算を導入し、プライバシー保護型の機械学習や統計に威力を発揮します。TFHE はブール回路を暗号化のまま柔軟に評価でき、ノイズ増大を抑えた高速ブートストラップが可能です。
格子暗号・LWE 問題・多項式環・剰余算といった数学的基礎が、FHE の安全性と計算能力を支えています。一方、Rust の実装例が示すように、これらの複雑な操作は実用的な API に抽象化され、開発者にとって扱いやすくなっています。
要点のまとめ:
- プライバシーと両立する計算:FHE はデータを明かさずに計算を可能にし、クラウド・医療・金融・共同研究に新しい可能性を開きます。
- 用途に応じた方式選択:さまざまな FHE 方式により、精度・性能・機能要件に応じた最適解を選べます。
- 進化の継続:現状は性能上の制約があるものの、研究と実装の進歩により実用性は着実に向上しています。
- 実装の実際:モダンなライブラリは数学的複雑さを隠蔽し、プライバシー保護アプリケーションの開発を容易にします。
今後、さらなる最適化、ハードウェアアクセラレーション、効率的なアルゴリズムが進展すれば、FHE はプライバシー保護計算の中核技術として幅広く普及するでしょう。Gentry の最初の構成から今日の実装に至る道のりは、理論暗号がデジタル世界を変える力を示しています。プライバシー規制が強化される時代において、FHE は「機密を保ったまま有用性を引き出す」という数学的保証を提供し、安全な計算の未来を形作ると期待されます。
参考文献
- Microsoft SEAL
- IBM HElib
- Google An FHE compiler for C++
- heir
- Zama Concrete
- Fully Homomorphic Encryption Using Ideal Lattices
- Learning with Errors
- Ring Learning with Errors
- Introduction to the BFV FHE Scheme
- Introduction to the BGV FHE Scheme
- Introduction to the CKKS/HEAAN FHE Scheme
- Hitchhiker’s Guide to the TFHE Scheme
- Chinese Remainder Theorem
- TFHE-rs
- OpenFHE-rs
このブログ記事の議論に参加してください:
この記事は AI 搭載の翻訳ツールによって翻訳されました。翻訳に誤りがある場合はご容赦ください。すぐに校正し、考えられる誤りを修正します。誤りを見つけた場合は、GitHub で問題を作成してください。