7月31日、Appleは新しいオープンソースのSwiftパッケージである「swift-homomorphic-encryption」を発表した。
ホモモルフィック暗号(HE)は、暗号化されたデータ上で計算を行うことができる暗号技術であり、計算プロセスにおいて基礎となる非暗号化データを明らかにすることがない。これにより、クライアントが暗号化されたデータをサーバーに送信し、その暗号化データに対して操作を行い、クライアントが復号化できる結果を返すことが可能となる。このプロセス中、サーバーは元のデータを復号化せず、復号鍵にもアクセスしない。このようなアプローチは、クラウドサービスがユーザーのデータのプライバシーとセキュリティを保護しながら動作する新たな機会を提供し、多くのシナリオにおいて非常に魅力的である。
(編注:ただし、ホモモルフィック暗号化技術には否定的な意見もある: テック大手、新「ホモモルフィック暗号化」を導入。ユーザーセキュリティの新時代か、またごまかしなのか(AdGuardブログ)
Appleでは、プライベートクラウドコンピュートなどの自社の業務にホモモルフィック暗号を利用しており、Swiftコミュニティにこの実装を共有できることを喜んでいる。
この実装の一例として、iOS 18で導入される新機能「ライブ発信者IDルックアップ」がある。これは、発信者IDとスパムブロッキングサービスを提供する機能であり、ホモモルフィック暗号を使用して特定の電話番号をサーバーに送信せずに問い合わせを行う。これを示すために、機能的なバックエンド例として「live-caller-id-lookup-example」を共有している。
これらのパッケージは、以下の機能をフルに活用している。
- Hummingbird HTTPフレームワークとクロスプラットフォームサポートを含むSwift on Server
- Benchmarkライブラリを使用した簡単なベンチマーキング
- Swift Cryptoの高性能な低レベル暗号化プリミティブ
ライブ発信者IDルックアップは、プライベート情報検索(PIR)という形式のプライベートキーバリューデータベース検索に依存している。PIR設定では、クライアントがプライベートなキーワード(例えば電話番号)を持ち、サーバーから関連する値を取得したいと考える。キーワードがプライベートであるため、 クライアントはサーバーがキーワードを知らない状態で検索を行いたい。
PIRの最も単純な実装方法としては、サーバーが全データベースをクライアントに送信してローカルで処理する方法が考えられる。これにより、サーバーがどのクエリが行われているかを知ることは防げるが、小さなデータベースでのみ現実的であり、更新頻度が低い場合に限られる。
一方、ホモモルフィック暗号に依存するPIR実装では、クライアントとのデータベースメタデータの同期が少量で済む。このメタデータは頻繁に変更されず、大規模なデータベースと高頻度の更新を効率的に処理できる。
ホモモルフィック暗号の典型的なワークフローは以下の通りである。
- クライアントが機密データを暗号化し、その結果をサーバーに送信する。
- サーバーが平文の入力を組み込むかもしれない暗号文に対して計算を行うが、どの暗号文が何を復号化するかは知らない。
- サーバーが結果の暗号文応答をクライアントに送信する。
- クライアントが結果の応答を復号化する。
Swiftでのホモモルフィック暗号の実装は、Brakerski-Fan-Vercauteren(BFV)HEスキーム(https://eprint.iacr.org/2012/078, https://eprint.iacr.org/2012/144)を実装している。BFVは、リング学習誤り(RLWE)ハードネス問題に基づいており、量子耐性がある。
ライブ発信者IDルックアップ機能は、クラシックおよび将来の量子攻撃に対する強力なセキュリティを提供するために、ポスト量子128ビットセキュリティを持つBFVパラメータを必要とする。
以下は、Swift Homomorphic Encryptionの基本的な使用例である。
import HomomorphicEncryption
// Bfv<UInt64>スキームの暗号化パラメータを選択する。
// *これらの暗号化パラメータはテストにのみ適した不安全なものである。*
let encryptParams =
try EncryptionParameters<Bfv<UInt64>>(from: .insecure_n_8_logq_5x18_logt_5)
// これらのパラメータでHE計算のための事前計算を行う。
let context = try Context(encryptionParameters: encryptParams)
// N個の値を係数エンコードを使用してエンコードする。
let values: [UInt64] = [8, 5, 12, 12, 15, 0, 8, 5]
let plaintext: Bfv<UInt64>.CoeffPlaintext = try context.encode(
values: values,
format: .coefficient)
// 秘密鍵を生成し、それを使用して平文を暗号化する。
let secretKey = try context.generateSecretKey()
let ciphertext = try plaintext.encrypt(using: secretKey)
// 平文を復号化すると、元の値が得られる。
let decrypted = try ciphertext.decrypt(using: secretKey)
let decoded: [UInt64] = try decrypted.decode(format: .coefficient)
precondition(decoded == values)
詳細はAnnouncing Swift Homomorphic Encryptionを参照していただきたい。