全くもって個人的な趣味ですが、「量子コンピューターって何が出来るんだろう」とふと考えてしまいます。
それで、「Shorのアルゴリズム使うと素因数分解が解けてしまうんだよ!」って言われると「へえ、じゃあなんでみんな騒がないの?」って聞くと「少なくとも1024ビットのRSA暗号だと1024量子ビット必要で、今の最大は128量子ビットだから、将来1万量子ビットとか10万量子ビットの量子コンピュータ出来るとエラー訂正用の量子ビットも併せて十分解読されてしまう時代になるけど、その1万とか10万になかなか時間が掛かると言われているからまだ平気だって思っているんだよ」と言われます。
でも暗号って記録は出来るから、将来10万量子ビットの量子コンピュータが誕生したらその瞬間から暗号が無意味になります。
そこでなんとかせねばと世界の叡智が集結して考えたのが、耐量子暗号です。
耐量子暗号は、GitHubからモジュールが提供されています。もちろん、クラッシックコンピュータで実装して使う事が出来ます。
ネットで情報を検索しても実装方法が分からなかったので、今流行の生成AIと会話して何とか実装プログラムを作って貰いました。誰でもやれますが、一応、ここに公開します。
ーーーーーーーーーーーー
耐量子暗号 (PQC) vs RSA暗号 対比講習
環境: qBraid (Python 3.11, Qiskit 2.1.1)
講師: (お名前や所属を記載)
日付: (実施日を記載)
0. はじめに
1. 背景と目的
現代のインターネット通信や電子署名など、多くのセキュリティ基盤は「素因数分解の困難性」や「離散対数問題の困難性」といった数学的な問題に依存しています。代表的な公開鍵暗号方式であるRSA暗号もその一つです。
しかし、大規模な汎用量子コンピュータが実現すると、ショアのアルゴリズムによってこれらの問題が効率的に解かれてしまう可能性が指摘されています。これは、現在の暗号システムが根本から脅かされることを意味します。
この脅威に対抗するため、量子コンピュータでも解読が困難とされる新しい暗号技術「耐量子暗号(Post-Quantum Cryptography, PQC)」の研究開発が進められています。アメリカ国立標準技術研究所(NIST)はPQCの標準化プロジェクトを進めており、2022年7月には最初の標準候補アルゴリズム群を発表し、2024年8月にはそのドラフト標準を発表しました。これらのアルゴリズムは、NSA(アメリカ国家安全保障局)も将来的な利用を推奨しています。
本講習では、
(1)古典的な公開鍵暗号であるRSA暗号の仕組みを理解し、Pythonで簡単な実装を試みます。
(2)量子コンピュータがRSA暗号に与える脅威(ショアのアルゴリズム)について概観します。
(3)NSA(NIST経由)が選定した耐量子暗号の概要と、その必要性について学びます。
(4)RSA暗号と耐量子暗号の主要な違いを比較します。
(5)Pythonライブラリを使って耐量子暗号の簡単な利用例に触れます。
2. 本講習で利用するツール
●Python 3.11
●Qiskit 2.1.1 (主にショアのアルゴリズムの文脈で触れます)
●Jupyter Notebook (qBraid環境)
●oqs (liboqs-python) パッケージ (PQCのデモ用。インストールが必要です)
3. qBraid環境の確認 (Qiskit)
まずはQiskitのバージョンを確認してみましょう。
# Code Cell
# Qiskitのバージョン確認
import qiskit
print(f"Qiskitのバージョン: {qiskit.__version__}")
# Qiskit 2.0.0以降では、qiskit.version が非推奨となり、代わりに qiskit.__version__ や qiskit.VERSION を使います。
# また、qiskit_terraはqiskitに統合されました。
1. RSA暗号の仕組みとPythonによる実装
RSA暗号は、1977年にRivest、Shamir、Adlemanによって発明された公開鍵暗号方式です。その安全性は、大きな合成数の素因数分解が計算機を使っても非常に困難であるという事実に依存しています。
1.1 RSA暗号の鍵生成
(1)2つの大きな素数 p, q を選ぶ。 (これらは秘密に保つ) 例: p = 61, q = 53 (実際にはもっとずっと大きな素数を使います)
(2)n = p * q を計算する。 (nは公開鍵の一部) n = 61 * 53 = 3233
(3)φ(n) = (p-1) * (q-1) を計算する。 (φ(n)はオイラーのトーシェント関数。秘密に保つ) φ(n) = (61-1) * (53-1) = 60 * 52 = 3120
(4)公開鍵 e を選ぶ。 e は 1 < e < φ(n) であり、φ(n) と互いに素である整数。 一般的に e = 65537 (2^16 + 1) がよく使われます。ここでは簡単な例として e = 17 を選びます。 gcd(17, 3120) = 1 (gcdは最大公約数)
(5)秘密鍵 d を計算する。 d は (d * e) mod φ(n) = 1 を満たす整数。 d * 17 ≡ 1 (mod 3120) d = 2753 (17 * 2753 = 46801 = 15 * 3120 + 1)
これで、
●公開鍵: (n, e) = (3233, 17)
●秘密鍵: (n, d) = (3233, 2753) (実際にはdだけで十分ですが、nも含むことがあります) (p, q, φ(n) も秘密情報です)
1.2 暗号化と復号
●暗号化: 平文メッセージ M (ただし 0 ≤ M < n) に対して、暗号文 C は以下のように計算される。 C = M^e mod n
●復号: 暗号文 C に対して、平文メッセージ M は以下のように計算される。 M = C^d mod n
1.3 PythonによるRSA暗号の簡単な実装
# Code Cell
import math
def gcd(a, b):
"""最大公約数を計算する関数"""
while b:
a, b = b, a % b
return a
def extended_gcd(a, b):
"""拡張ユークリッド互除法により ax + by = gcd(a,b) の解 (x,y) と gcd(a,b) を返す"""
if a == 0:
return b, 0, 1
d, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return d, x, y
def mod_inverse(e, phi_n):
"""モジュラ逆数 d ( e*d ≡ 1 (mod phi_n) ) を計算する関数"""
d, x, y = extended_gcd(e, phi_n)
if d != 1:
raise Exception('モジュラ逆数は存在しません (eとphi_nが互いに素ではない)')
return x % phi_n
# 1. 2つの素数 p, q (実際には非常に大きな素数)
p = 61
q = 53
print(f"p = {p}, q = {q}")
# 2. n と φ(n) の計算
n = p * q
phi_n = (p - 1) * (q - 1)
print(f"n = {n}")
print(f"φ(n) = {phi_n}")
# 3. 公開鍵 e の選択 (1 < e < φ(n) で φ(n)と互いに素)
e = 17 # 一般的には65537など
if not (1 < e < phi_n and gcd(e, phi_n) == 1):
raise ValueError("eの値が不適切です。")
print(f"公開鍵 e = {e}")
# 4. 秘密鍵 d の計算 (d * e ≡ 1 (mod φ(n)))
d = mod_inverse(e, phi_n)
print(f"秘密鍵 d = {d}")
print(f"\n公開鍵: (n={n}, e={e})")
print(f"秘密鍵: d={d} (p,q,phi_nも秘密)") # 実際にはdだけで秘密鍵とされることが多い
# --- 暗号化と復号のテスト ---
message_str = "HELLO"
print(f"\n元のメッセージ文字列: {message_str}")
# 簡単のため、各文字をASCII値として個別に暗号化する
# (実際にはパディングスキーマなど、より高度な方法が使われる)
message_numerical = [ord(char) for char in message_str]
print(f"数値に変換したメッセージ: {message_numerical}")
# 暗号化 (C = M^e mod n)
# Pythonのpow(base, exp, mod)は効率的なモジュラべき乗計算を行う
encrypted_message = [pow(m_char, e, n) for m_char in message_numerical]
print(f"暗号化されたメッセージ (数値): {encrypted_message}")
# 復号 (M = C^d mod n)
decrypted_numerical = [pow(c_char, d, n) for c_char in encrypted_message]
print(f"復号されたメッセージ (数値): {decrypted_numerical}")
decrypted_message_str = "".join([chr(num) for num in decrypted_numerical])
print(f"復号されたメッセージ文字列: {decrypted_message_str}")
assert message_numerical == decrypted_numerical
print("\n暗号化・復号テスト成功!")
演習:
(1)p と q の値を他の小さな素数に変えて、正しく動作することを確認してみましょう。
(2)e の値を、phi_n と互いに素な別の値に変えてみましょう。(例: e = 7 など)
2. ショアのアルゴリズムとRSAへの脅威
RSA暗号の安全性は「大きな数の素因数分解が困難である」という仮定に基づいています。もし n を効率的に素因数分解して p と q を見つけることができれば、φ(n) が計算でき、秘密鍵 d も容易に導出できてしまいます。
古典コンピュータでは、n のビット長に対して指数関数的な時間が必要とされ、現在の技術では現実的な時間内に解読不可能な大きさの n (例: 2048ビットや4096ビット) が使われています。
2.1 ショアのアルゴリズム
1994年、ピーター・ショアは、量子コンピュータを用いることで整数を効率的に素因数分解できるアルゴリズムを発表しました。これは、量子ビット長 L = log2(N) に対して、多項式時間 O(L^3) で動作します。
ショアのアルゴリズムの主要なステップ(簡略版):
(1)分解したい数 N より小さく、N と互いに素な数 a をランダムに選ぶ。
(2)関数 f(x) = a^x mod N の周期 r を見つける。 ここが量子コンピュータの能力が活かされる部分(量子フーリエ変換を用いた位数推定)。
(3)もし r が偶数で、a^(r/2) ≠ -1 (mod N) ならば、gcd(a^(r/2) - 1, N) と gcd(a^(r/2) + 1, N) が N の非自明な因数である可能性が高い。
(4)もし失敗したら、a を変えて繰り返す。
2.2 Qiskitとショアのアルゴリズム
Qiskitは、ショアのアルゴリズムを含む様々な量子アルゴリズムを実装し、シミュレート・実行するためのフレームワークです。 実際にQiskitでショアのアルゴリズムを動かすコードは、量子回路の構成、量子フーリエ変換、位数推定アルゴリズムなど、より専門的な知識を要します。
Qiskitのバージョンアップに伴う注意: Qiskitはバージョン1.0以降で大きなAPIの変更がありました。特に、アルゴリズムの実行方法や、qiskit.algorithms モジュールが外部パッケージ qiskit_algorithms に分離された点などが重要です。QuantumInstance クラスはQiskit 1.0で非推奨となり、Qiskit 2.0では利用できません。
ショアのアルゴリズムの概念: ここでは、Qiskitを使ってショアのアルゴリズムが「何をするのか」を概念的に示します。 以下のコードは、ショアのアルゴリズムが N=15 を素因数分解する「雰囲気」を示すものであり、Qiskit 2.1.1の環境でそのまま動作する完全な実行コードではありません。
# Qiskit 2.1.1環境であることを確認
import qiskit
print(f"Qiskitのバージョン: {qiskit.__version__}")
# --- 概念的な説明のためのコード ---
# Qiskit 1.0以降、qiskit.algorithms は qiskit_algorithms パッケージに分離されました。
# qBraid環境に qiskit_algorithms がプリインストールされているか確認が必要です。
# もしインストールされていなければ、ターミナルで `pip install qiskit_algorithms` でインストールできます。
N = 15
print(f"\nショアのアルゴリズムで素因数分解を試みる数: N = {N}")
print("\n--- ショアのアルゴリズム実行の概念 (Qiskit 2.0では以下のコードは直接動作しません) ---")
# 以前のQiskitバージョン (0.x系) では、以下のような形でShorアルゴリズムを利用できました。
# from qiskit.algorithms import Shor # 古いインポートパス
# from qiskit.utils import QuantumInstance # Qiskit 1.0で非推奨、2.0で削除
# from qiskit_aer import AerSimulator
# Qiskit 1.0以降では qiskit_algorithms パッケージを使います。
# APIも変更されており、SamplerやEstimatorプリミティブと連携する形になります。
# 例 (qiskit_algorithms がインストールされている場合 - このコードもAPI変更により動作しない可能性あり):
# from qiskit_algorithms.factorizers import Shor
# from qiskit.primitives import Sampler
# sampler = Sampler()
# shor_factorizer = Shor(sampler=sampler)
# result = shor_factorizer.factor(N)
# print(f"結果: {result}")
print("\n--- ショアのアルゴリズムの「結果」についての説明 ---")
# Qiskitを用いてショアのアルゴリズムを正しく実装・実行すると、
# N=15 の場合、その素因数である (3, 5) が得られます。
p_factor = 3
q_factor = 5
print(f"ショアのアルゴリズムが N={N} に対して見つけるであろう素因数: {p_factor}, {q_factor}")
# これにより、RSA暗号がどのように破られるか:
if N == p_factor * q_factor:
phi_n_reconstructed = (p_factor - 1) * (q_factor - 1)
print(f"素因数が分かれば、φ(N) = ({p_factor}-1)*({q_factor}-1) = {phi_n_reconstructed} が計算できます。")
print(f"φ(N)が分かれば、公開鍵 e から秘密鍵 d を計算することが可能になり、RSA暗号は解読されます。")
else:
print("計算が合いません。Nの値と因数を確認してください。")
print("\nこれが、量子コンピュータがRSA暗号にとって脅威となる理由です。")
print("実際にQiskitでショアのアルゴリズムをステップ・バイ・ステップで実行するには、")
print("より詳細なチュートリアル(例えば、ご提示いただいたUTokyo ICEPPの教材など)を参照してください。")
print("その際、QiskitのバージョンによるAPIの違いに注意が必要です。")
# 参考: UTokyo Qiskit Textbook (日本語) のショアのアルゴリズムの章
# https://utokyo-icepp.github.io/qc-workbook/ja/shor.html
# (Qiskitのバージョンによる違いに注意して参照してください)
重要な点:
●現在実用化されている量子コンピュータはまだ小規模であり、RSA-2048のような巨大な数を素因数分解するには至っていません。
●しかし、技術の進展は速く、将来的に大規模な量子コンピュータが登場するリスクに備える必要があります。これが耐量子暗号(PQC)が求められる理由です。
3. 耐量子暗号 (PQC) とは
耐量子暗号(Post-Quantum Cryptography, PQC)は、現在の古典コンピュータだけでなく、将来登場する可能性のある大規模量子コンピュータに対しても安全性を維持できるように設計された暗号アルゴリズム群です。
重要なのは、PQCアルゴリズム自体は古典コンピュータ上で動作するという点です。量子コンピュータを使って暗号化や復号を行うわけではありません。「量子コンピュータによる攻撃に耐えられる」ように設計された古典的なアルゴリズムです。
PQCの主なアプローチには、以下のような数学的問題に基づいたものがあります。
(1)格子ベース暗号 (Lattice-based cryptography): 「最近ベクトル問題 (Closest Vector Problem, CVP)」や「最短ベクトル問題 (Shortest Vector Problem, SVP)」、またそれらに関連する「学習用誤りあり問題 (Learning With Errors, LWE)」などの格子上の困難な問題に基づきます。NISTの選定アルゴリズムの多くがこれに該当します。
(2)符号ベース暗号 (Code-based cryptography): 「一般的な線形符号の復号問題」の困難性に基づきます。McEliece暗号が古典的な例です。
(3)ハッシュベース署名 (Hash-based signatures): 暗号学的ハッシュ関数の安全性のみに依存します。状態管理が必要なものと不要なものがあります。
(4)多変数公開鍵暗号 (Multivariate cryptography): 多変数多項式方程式の系を解くことの困難性に基づきます。
(5)同種写像暗号 (Isogeny-based cryptography): 楕円曲線間の同種写像を計算する問題の困難性に基づきます。SIKEが有名でしたが、最近脆弱性が発見されました。
4. NSAが選定した耐量子暗号アルゴリズム(NIST PQC標準化プロセス)
NSAは直接PQCアルゴリズムを選定するのではなく、NIST (アメリカ国立標準技術研究所) が主導するPQC標準化プロセスを支援し、その結果を将来のシステムに採用する方針を示しています。
NISTは2016年にPQCの公募を開始し、数ラウンドの評価を経て、2022年7月に最初の標準化対象アルゴリズムを発表しました。そして、2024年8月にこれらのアルゴリズムのドラフト標準 (FIPS 203, FIPS 204, FIPS 205) を公開しました。
4.1 NIST PQC 標準化 (ドラフト標準公開済み)
公開鍵暗号化/鍵カプセル化メカニズム (KEM - Key Encapsulation Mechanism):
●CRYSTALS-Kyber (ML-KEM) (FIPS 203)
■格子ベース暗号 (Module-LWE問題に基づく)
■バランスの取れた性能と鍵長を持つ。
デジタル署名:
●CRYSTALS-Dilithium (ML-DSA) (FIPS 204)
■格子ベース暗号 (Module-LWEおよびModule-SIS問題に基づく)
■比較的短い署名と公開鍵/秘密鍵。
●Falcon (FIPS 205 に含まれる見込み、要確認)
■格子ベース暗号 (NTRU構造上のShort Integer Solution (SIS) 問題に基づく)
■非常に短い署名と公開鍵が特徴だが、署名生成が複雑。
●SPHINCS+ (SLH-DSA) (FIPS 205)
■ハッシュベース署名 (ステートレス)
■他の格子ベース署名より署名サイズが大きいが、セキュリティの仮定がハッシュ関数の安全性のみと非常に堅牢。
4.2 これらのアルゴリズムの簡単な特徴 (例: Kyber)
CRYSTALS-Kyber (ML-KEM) は、鍵共有や公開鍵暗号化に使用されるKEMです。
●安全性: Module Learning With Errors (MLWE) 問題の困難性に基づいています。これは、ある行列 A と小さなノイズベクトル e、秘密ベクトル s があったとき、b = As + e という関係から s を見つけるのが難しい、という問題です。
●動作の概略 (非常に簡略化):
(1)鍵生成: 受信者は秘密鍵 s と公開鍵 (行列 A と t = As + e のような値) を生成。
(2)カプセル化 (暗号化側): 送信者は受信者の公開鍵を使って、共通鍵 K とその暗号文 (カプセル化された鍵 c) を生成。
(3)非カプセル化 (復号側): 受信者は秘密鍵 s とカプセル化された鍵 c を使って共通鍵 K を復元。
●この共通鍵 K を使って、AESなどの共通鍵暗号で実際のデータを暗号化します。
5. RSAと耐量子暗号の比較
●PQCアルゴリズムは種類が多く、それぞれ特性(鍵長、速度、暗号文/署名サイズ)が異なります。
●ハイブリッドモード: 安全性の移行期間として、従来のRSA/ECCとPQCを組み合わせて使うアプローチも検討されています。
6. qBraid環境でのPQCライブラリ利用 (概念実証)
PQCアルゴリズムをQiskitで「実装」するわけではありません。PQCは古典アルゴリズムなので、Pythonのライブラリとして利用します。 liboqs というオープンソースライブラリがあり、多くのNIST PQC候補アルゴリズムをC言語で実装しています。これにはPythonラッパー liboqs-python があり、PyPIパッケージ名は oqs です。
インストールの注意: oqs という名前の別のPythonパッケージ (Open Quick Script) が存在するため、単純に pip install oqs とすると、意図しない方がインストールされます。また、liboqs-python はCライブラリに依存するため、ビルドツール (gcc, cmake) や依存ライブラリ (OpenSSL 開発パッケージ) が必要です。 qBraid環境で正しくインストールするには、以下の手順が必要でした(ターミナルで実行)。
(1)競合する oqs (Open Quick Script) があればアンインストール (!pip uninstall oqs -y)。
(2)依存するOpenSSL開発パッケージをインストール (!sudo apt-get update && sudo apt-get install -y libssl-dev または !conda install openssl libopenssl-static)。
(3)公式GitHubリポジトリから特定のタグを指定してインストール (!pip install git+https://github.com/open-quantum-safe/liboqs-python.git@0.12.0)。
もしインストールがうまくいかない場合は、このセクションのコードは実行できません。
以下のコードは、liboqs-python (oqs) が正しくインストールされた環境で動作します。
## oqsをインストールするための3つのステップも実行する
# 1. 競合する `oqs` (Open Quick Script) があればアンインストール
!pip uninstall oqs -y
# 2. 依存するOpenSSL開発パッケージをインストール
!sudo apt-get update && sudo apt-get install -y libssl-dev
# !conda install openssl libopenssl-static
# Code Cell (6節の最終版コード)
try:
import oqs
# バージョン情報を取得 (oqsモジュール直下の関数を使用)
version_info = f"oqs_version={oqs.oqs_version()}, python_wrapper_version={oqs.oqs_python_version()}"
print(f"liboqs-python (oqs) が正常にインポートされました。{version_info}")
pqc_available = True
except ImportError:
print("liboqs-python (oqs) が見つかりません。インストールが必要です。")
print("上記の「インストールの注意」を参照してください。")
pqc_available = False
except Exception as e:
print(f"oqsインポートまたはバージョン確認中にエラー: {e}")
pqc_available = False # エラー時は利用不可とする
if pqc_available:
available_kems = []
available_sigs = []
try:
# --- KEMリスト取得 ---
# oqsモジュール直下の関数を使用
if hasattr(oqs, 'get_supported_kem_mechanisms') and callable(oqs.get_supported_kem_mechanisms):
available_kems = oqs.get_supported_kem_mechanisms()
print("\noqs.get_supported_kem_mechanisms() でKEMリストを取得しました。")
else:
if hasattr(oqs, 'get_enabled_kem_mechanisms') and callable(oqs.get_enabled_kem_mechanisms):
available_kems = oqs.get_enabled_kem_mechanisms()
print("\n警告: get_supported_kem_mechanisms が見つからず、get_enabled_kem_mechanisms() を使用しました。")
else:
raise AttributeError("KEMリスト取得関数 (get_supported_kem_mechanisms) が見つかりませんでした。")
# --- Signatureリスト取得 ---
if hasattr(oqs, 'get_supported_sig_mechanisms') and callable(oqs.get_supported_sig_mechanisms):
available_sigs = oqs.get_supported_sig_mechanisms()
print("oqs.get_supported_sig_mechanisms() でSignatureリストを取得しました。")
else:
if hasattr(oqs, 'get_enabled_sig_mechanisms') and callable(oqs.get_enabled_sig_mechanisms):
available_sigs = oqs.get_enabled_sig_mechanisms()
print("警告: get_supported_sig_mechanisms が見つからず、get_enabled_sig_mechanisms() を使用しました。")
else:
raise AttributeError("Signatureリスト取得関数 (get_supported_sig_mechanisms) が見つかりませんでした。")
# --- リスト表示 ---
print("\n利用可能なKEMアルゴリズム (NIST選定関連のみ表示):")
nist_kems = [kem for kem in available_kems if "Kyber" in kem or "ML-KEM" in kem]
for kem_name in nist_kems: print(f"- {kem_name}")
if not nist_kems: print("NIST選定に関連するKEMが見つかりませんでした。")
print("\n利用可能な署名アルゴリズム (NIST選定関連のみ表示):")
nist_sigs = [sig for sig in available_sigs if "Dilithium" in sig or "ML-DSA" in sig or "Falcon" in sig or "SPHINCS+" in sig or "SLH-DSA" in sig]
# 表示数が多いので一部のみ表示
for i, sig_name in enumerate(nist_sigs):
if i < 15: print(f"- {sig_name}")
elif i == 15: print("...")
if not nist_sigs: print("NIST選定に関連する署名アルゴリズムが見つかりませんでした。")
# --- CRYSTALS-Kyber (ML-KEM) デモ ---
kem_alg_name = None
# リストからKyber512を探す (ML-KEM-512があればそれでも良い)
possible_kyber_names = ["Kyber512", "ML-KEM-512"]
for name_try in possible_kyber_names:
if name_try in available_kems:
kem_alg_name = name_try
break
if kem_alg_name:
print(f"\n--- {kem_alg_name} KEM デモ ---")
# KeyEncapsulation クラスは oqs 直下
if not hasattr(oqs, 'KeyEncapsulation'):
raise AttributeError("KeyEncapsulationクラスが見つかりません。")
kem_server = oqs.KeyEncapsulation(kem_alg_name)
kem_client = oqs.KeyEncapsulation(kem_alg_name)
print(f"{kem_alg_name} 用に oqs.KeyEncapsulation を使用します。")
# 1. サーバーが鍵ペア生成
public_key_server = kem_server.generate_keypair()
print(f"公開鍵の長さ: {len(public_key_server)} バイト")
# 秘密鍵は kem_server オブジェクト内に保持される
# 2. クライアントがサーバーの公開鍵を使って共通鍵をカプセル化
ciphertext, shared_secret_client = kem_client.encap_secret(public_key_server)
print(f"暗号文(カプセル化された鍵)の長さ: {len(ciphertext)} バイト")
# 3. サーバーがクライアントから受け取った暗号文と自身の秘密鍵で共通鍵を非カプセル化
shared_secret_server = kem_server.decap_secret(ciphertext)
# 4. 両者の共通鍵が一致するか確認
if shared_secret_client == shared_secret_server:
print(f"\n成功: {kem_alg_name} を使って共通秘密鍵が一致しました!")
print(f"共通秘密鍵 (最初の16バイト): {shared_secret_client[:16].hex()}...")
else:
print(f"\n失敗: {kem_alg_name} の共通秘密鍵が一致しませんでした。")
else:
print("\n利用可能なKEMアルゴリズムに Kyber512 / ML-KEM-512 が見つかりませんでした。")
if available_kems: print(f"利用可能な全KEMリストの一部: {available_kems[:10]}...") # 多すぎる場合があるので一部表示
except AttributeError as e:
print(f"\noqsモジュールの使用中にエラーが発生しました: {e}")
print("liboqs-pythonのバージョンやAPIを確認してください。")
except Exception as e:
print(f"\nPQCデモの実行中に予期せぬエラーが発生しました: {e}")
7. まとめ
●RSA暗号は現代の多くのセキュリティシステムを支える重要な公開鍵暗号ですが、大規模量子コンピュータの登場によりショアのアルゴリズムによって破られる危険性があります。
●この脅威に対応するため、量子コンピュータでも解読困難な耐量子暗号 (PQC) の研究開発と標準化が進められています。
●NISTはPQC標準化プロジェクトを主導し、CRYSTALS-Kyber (KEM), CRYSTALS-Dilithium (署名), Falcon (署名), SPHINCS+ (署名) などを最初の標準候補として選定し、ドラフト標準を公開しました。これらはNSAも採用を推奨しています。
●PQCは一般的にRSAと比較して鍵長が大きくなるなどのトレードオフがありますが、量子時代に向けたセキュリティ確保のために不可欠です。
●Qiskitはショアのアルゴリズムのような量子アルゴリズムを探求するツールであり、PQCアルゴリズム(古典)自体をQiskitで実装するわけではありませんが、PQCの必要性を理解する上で量子アルゴリズムの知識は有益です。
●liboqs-python (oqs パッケージ) のようなライブラリを使うことで、Python環境でもPQCアルゴリズムを試すことができます(環境設定が必要な場合があります)。
今後の暗号技術の移行は段階的に進むと考えられます。PQCへの関心を持ち、動向を注視していくことが重要です。
8. 参考文献・資料
●NIST Post-Quantum Cryptography Project: https://csrc.nist.gov/Projects/post-quantum-cryptography
●NIST PQC Selected Algorithms (2022): https://www.nist.gov/news-events/news/2022/07/nist-announces-first-four-quantum-resistant-cryptographic-algorithms
●NIST PQC Draft Standards (FIPS 203, 204, 205):
■FIPS 203 (ML-KEM / Kyber): https://csrc.nist.gov/pubs/fips/203/ipd
■FIPS 204 (ML-DSA / Dilithium): https://csrc.nist.gov/pubs/fips/204/ipd
■FIPS 205 (SLH-DSA / SPHINCS+): https://csrc.nist.gov/pubs/fips/205/ipd
●Open Quantum Safe (OQS) Project: https://openquantumsafe.org/
■liboqs: https://github.com/open-quantum-safe/liboqs
■liboqs-python (oqs package): https://github.com/open-quantum-safe/liboqs-python
●Qiskit Documentation: https://qiskit.org/documentation/
●UTokyo ICEPP QC Workbook - ショアのアルゴリズム: https://utokyo-icepp.github.io/qc-workbook/ja/shor.html (ご提示のリンク)