0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

量子コンピュータが金融暗号を破る日に備える——PQC・QKD・暗号アジリティの実装ガイド【エンジニア向け】

0
Posted at

量子コンピュータが金融暗号を破る日に備える——PQC・QKD・暗号アジリティの実装ガイド

対象読者:セキュリティエンジニア、バックエンドエンジニア、フィンテック開発者、暗号技術に興味のある開発者全般
この記事でわかること:量子コンピュータの暗号への脅威・NISTが標準化したPQCアルゴリズムの導入手順・暗号アジリティの設計手法・QKDシミュレーションの始め方


はじめに——「安全」の前提が崩れる日

現在、ネットバンキング・株取引・クレジット決済を守っているのは RSA暗号楕円曲線暗号(ECC) です。その安全性は「大きな数の素因数分解は現在のコンピュータでは事実上不可能」という数学的前提に依存しています。

しかし1994年、数学者ピーター・ショアが発表した 「ショアのアルゴリズム」 により、十分な量子ビットを持つ量子コンピュータがあればRSA暗号を多項式時間で解読できることが理論的に証明されました。

IBMは2025年に2000量子ビットを超えるプロセッサを発表済み。このまま進化が続けば、10年以内に現在の金融インフラを守る暗号の壁が崩壊します。

本記事では「理論」にとどまらず、今すぐ実装できる量子耐性の技術と手順を具体的に解説します。


1. 脅威の構造を理解する

1-1. ショアのアルゴリズムで何が破られるか

現在の暗号 → 解読に必要な時間(従来コンピュータ)→ 量子コンピュータでの解読時間
─────────────────────────────────────────────────
RSA-2048   → 約138億年(宇宙の年齢以上)            → 数時間〜数日(理論値)
ECC P-256  → 宇宙の年齢の何倍も                     → 同様に破壊可能
AES-256    → 事実上不可能                            → 安全性は半減するが依然有効
SHA-256    → 事実上不可能                            → 安全性は半減するが依然有効
  • RSA・ECCは量子コンピュータに対して壊滅的に脆弱
  • AES・SHA系は量子後も(鍵長を増やすことで)有効

1-2. 今すぐ始まっている「Harvest Now, Decrypt Later(HNDL)攻撃」

量子コンピュータが完成していなくても、攻撃はすでに始まっています。

【HNDL攻撃の流れ】

攻撃者 ──── 今日の暗号化通信を盗聴 ──→ 大容量ストレージに保存
                                                ↓
                                      量子コンピュータ完成(Xデー)
                                                ↓
                                      過去の通信を一括解読
                                                ↓
                                      銀行口座・取引記録・個人情報が露出

NSAは2022年時点でこの脅威を警告し、即時の対応計画策定を促しています。長期保存が必要なデータほど今すぐ対処が必要です。


2. NIST標準PQCアルゴリズムの概要

2024年8月、NIST(米国立標準技術研究所)が Post-Quantum Cryptography の標準を正式発表しました。

標準名 旧称 用途 数学的基盤
ML-KEM CRYSTALS-Kyber 鍵カプセル化(鍵交換) 格子暗号(Module-LWE)
ML-DSA CRYSTALS-Dilithium デジタル署名 格子暗号(Module-LWE/SIS)
SLH-DSA SPHINCS+ デジタル署名 ハッシュベース

格子暗号とは(直感的に理解する)

高次元空間(例:1000次元)に格子点(等間隔の点の集合)が存在する
      ↓
「最も近い格子点を見つけよ」という問題(最近格子点問題:CVP/SVP)
      ↓
量子コンピュータでも多項式時間では解けないと考えられている
      ↓
この計算困難性が暗号の安全性を支える

3. 環境構築——PQC開発を始める

3-1. liboqs(Open Quantum Safe)のインストール

NISTが標準化したアルゴリズムを含む、最も広く使われているオープンソースPQCライブラリです。

macOS / Linux の場合

# 依存パッケージのインストール
# macOS
brew install cmake ninja openssl

# Ubuntu / Debian
sudo apt-get install -y cmake ninja-build libssl-dev python3-dev

# liboqsのビルド(C言語コア)
git clone https://github.com/open-quantum-safe/liboqs.git
cd liboqs
mkdir build && cd build
cmake -GNinja -DBUILD_SHARED_LIBS=ON ..
ninja
sudo ninja install

# Pythonバインディング(oqs-python)のインストール
pip install oqs

Windowsの場合(WSL2推奨)

# WSL2(Ubuntu)上で上記のUbuntu手順を実行
# または Docker を使用
docker pull openquantumsafe/oqs-ossl3
docker run -it openquantumsafe/oqs-ossl3 bash

動作確認

import oqs

# 利用可能なアルゴリズム一覧を確認
print("=== 利用可能なKEMアルゴリズム ===")
for alg in oqs.get_enabled_kem_mechanisms():
    print(f"  {alg}")

print("\n=== 利用可能な署名アルゴリズム ===")
for alg in oqs.get_enabled_sig_mechanisms():
    print(f"  {alg}")

4. ML-KEM(Kyber)——鍵交換の実装

ML-KEMは、現在のTLSで使われるDH鍵交換の量子耐性版です。

4-1. 基本的な鍵カプセル化の実装

import oqs

# ML-KEM-768を使った鍵交換のシミュレーション
# (ML-KEM-512: 軽量版、ML-KEM-1024: 最高セキュリティ)

def kyber_key_exchange_demo():
    alg_name = "ML-KEM-768"  # NIST標準(セキュリティレベル3)
    
    print(f"=== {alg_name} 鍵交換デモ ===\n")
    
    # ── Alice側(受信者)──
    with oqs.KeyEncapsulation(alg_name) as alice:
        # 公開鍵・秘密鍵のペアを生成
        alice_public_key = alice.generate_keypair()
        
        print(f"[Alice] 公開鍵サイズ: {len(alice_public_key)} バイト")
        print(f"[Alice] 公開鍵(先頭32バイト): {alice_public_key[:32].hex()}")
        
        # ── Bob側(送信者)──
        with oqs.KeyEncapsulation(alg_name) as bob:
            # Aliceの公開鍵を使って暗号文と共有鍵を生成
            ciphertext, bob_shared_secret = bob.encap_secret(alice_public_key)
            
            print(f"\n[Bob] 暗号文サイズ: {len(ciphertext)} バイト")
            print(f"[Bob] 共有鍵(Bob側): {bob_shared_secret.hex()}")
        
        # AliceがBobの暗号文から共有鍵を復元
        alice_shared_secret = alice.decap_secret(ciphertext)
        print(f"\n[Alice] 共有鍵(Alice側): {alice_shared_secret.hex()}")
        
        # 鍵が一致しているか確認
        match = alice_shared_secret == bob_shared_secret
        print(f"\n✅ 共有鍵の一致: {match}")
        
        return alice_shared_secret

shared_key = kyber_key_exchange_demo()

4-2. ML-KEM + AES-256 によるハイブリッド暗号化

現実のシステムでは、ML-KEMで鍵交換し、その鍵でAES暗号化するハイブリッド方式が推奨されます。

import oqs
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

def hybrid_encrypt(plaintext: bytes, recipient_public_key: bytes) -> dict:
    """
    ML-KEM + AES-256-GCM によるハイブリッド暗号化
    """
    alg_name = "ML-KEM-768"
    
    with oqs.KeyEncapsulation(alg_name) as kem:
        # ML-KEMで32バイトの共有鍵を生成
        ciphertext, shared_secret = kem.encap_secret(recipient_public_key)
    
    # AES-256-GCMでメッセージを暗号化(nonce=12バイト)
    nonce = os.urandom(12)
    aesgcm = AESGCM(shared_secret[:32])  # 32バイト=256ビット
    encrypted_message = aesgcm.encrypt(nonce, plaintext, None)
    
    return {
        "kem_ciphertext": ciphertext,
        "nonce": nonce,
        "encrypted_message": encrypted_message
    }


def hybrid_decrypt(package: dict, private_key_context) -> bytes:
    """
    ML-KEM + AES-256-GCM によるハイブリッド復号
    """
    # ML-KEMで共有鍵を復元
    shared_secret = private_key_context.decap_secret(package["kem_ciphertext"])
    
    # AES-256-GCMで復号
    aesgcm = AESGCM(shared_secret[:32])
    return aesgcm.decrypt(package["nonce"], package["encrypted_message"], None)


# 使用例
alg_name = "ML-KEM-768"
with oqs.KeyEncapsulation(alg_name) as recipient:
    public_key = recipient.generate_keypair()
    
    # 暗号化
    message = b"This is a quantum-safe secret message for financial data"
    package = hybrid_encrypt(message, public_key)
    
    # 復号
    decrypted = hybrid_decrypt(package, recipient)
    
    print(f"元メッセージ: {message}")
    print(f"復号メッセージ: {decrypted}")
    print(f"一致: {message == decrypted}")

5. ML-DSA(Dilithium)——デジタル署名の実装

金融取引の認証・改ざん防止に使われるデジタル署名の量子耐性版です。

import oqs

def dilithium_signature_demo():
    alg_name = "ML-DSA-65"  # NIST標準(セキュリティレベル3)
    # 他の選択肢: ML-DSA-44(軽量)、ML-DSA-87(最高セキュリティ)
    
    print(f"=== {alg_name} デジタル署名デモ ===\n")
    
    with oqs.Signature(alg_name) as signer:
        # 鍵ペアの生成
        public_key = signer.generate_keypair()
        
        print(f"公開鍵サイズ: {len(public_key)} バイト")
        
        # 署名対象メッセージ(金融取引データを想定)
        transaction = {
            "from": "account_A",
            "to": "account_B",
            "amount": 1000000,  # 100万円
            "timestamp": "2026-04-14T10:16:00Z"
        }
        import json
        message = json.dumps(transaction, ensure_ascii=False).encode()
        
        # 署名
        signature = signer.sign(message)
        print(f"署名サイズ: {len(signature)} バイト")
        
        # 署名の検証
        with oqs.Signature(alg_name) as verifier:
            is_valid = verifier.verify(message, signature, public_key)
            print(f"\n✅ 署名検証: {is_valid}")
            
            # 改ざんテスト
            tampered_message = message.replace(b"1000000", b"9999999")
            is_tampered_valid = verifier.verify(tampered_message, signature, public_key)
            print(f"❌ 改ざんデータの署名検証: {is_tampered_valid}")

dilithium_signature_demo()

6. 暗号アジリティ(Crypto Agility)の実装

先進的な金融機関が採用している「暗号方式をいつでも素早く差し替えられる設計」を実装します。

6-1. 暗号アジリティの設計パターン

from abc import ABC, abstractmethod
from typing import Tuple
import oqs
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization

class CryptoProvider(ABC):
    """暗号プロバイダーの抽象基底クラス(アジリティの核心)"""
    
    @abstractmethod
    def generate_keypair(self) -> Tuple[bytes, bytes]:
        """(public_key, private_key) を返す"""
        pass
    
    @abstractmethod
    def sign(self, message: bytes, private_key: bytes) -> bytes:
        pass
    
    @abstractmethod
    def verify(self, message: bytes, signature: bytes, public_key: bytes) -> bool:
        pass
    
    @property
    @abstractmethod
    def algorithm_name(self) -> str:
        pass


class RSAProvider(CryptoProvider):
    """従来のRSA-2048(移行期間中のレガシー対応用)"""
    
    @property
    def algorithm_name(self) -> str:
        return "RSA-2048"
    
    def generate_keypair(self) -> Tuple[bytes, bytes]:
        private_key = rsa.generate_private_key(
            public_exponent=65537, key_size=2048
        )
        pub_bytes = private_key.public_key().public_bytes(
            serialization.Encoding.DER,
            serialization.PublicFormat.SubjectPublicKeyInfo
        )
        priv_bytes = private_key.private_bytes(
            serialization.Encoding.DER,
            serialization.PrivateFormat.PKCS8,
            serialization.NoEncryption()
        )
        return pub_bytes, priv_bytes
    
    def sign(self, message: bytes, private_key: bytes) -> bytes:
        from cryptography.hazmat.primitives.serialization import load_der_private_key
        key = load_der_private_key(private_key, password=None)
        return key.sign(message, padding.PKCS1v15(), hashes.SHA256())
    
    def verify(self, message: bytes, signature: bytes, public_key: bytes) -> bool:
        from cryptography.hazmat.primitives.serialization import load_der_public_key
        try:
            key = load_der_public_key(public_key)
            key.verify(signature, message, padding.PKCS1v15(), hashes.SHA256())
            return True
        except Exception:
            return False


class MLDSAProvider(CryptoProvider):
    """NIST標準 ML-DSA(量子耐性デジタル署名)"""
    
    def __init__(self, variant: str = "ML-DSA-65"):
        self._variant = variant
    
    @property
    def algorithm_name(self) -> str:
        return self._variant
    
    def generate_keypair(self) -> Tuple[bytes, bytes]:
        with oqs.Signature(self._variant) as sig:
            public_key = sig.generate_keypair()
            private_key = sig.export_secret_key()
        return public_key, private_key
    
    def sign(self, message: bytes, private_key: bytes) -> bytes:
        with oqs.Signature(self._variant, secret_key=private_key) as sig:
            return sig.sign(message)
    
    def verify(self, message: bytes, signature: bytes, public_key: bytes) -> bool:
        with oqs.Signature(self._variant) as sig:
            return sig.verify(message, signature, public_key)


class CryptoAgileService:
    """
    暗号アジリティを実装したサービス層
    アルゴリズムを差し替えてもAPIが変わらない設計
    """
    
    def __init__(self, provider: CryptoProvider):
        self._provider = provider
        self._keys = {}
    
    def setup_keys(self, key_id: str) -> str:
        pub, priv = self._provider.generate_keypair()
        self._keys[key_id] = {"public": pub, "private": priv}
        return key_id
    
    def sign_transaction(self, key_id: str, transaction: dict) -> dict:
        import json
        message = json.dumps(transaction, sort_keys=True).encode()
        signature = self._provider.sign(message, self._keys[key_id]["private"])
        return {
            "transaction": transaction,
            "signature": signature.hex(),
            "algorithm": self._provider.algorithm_name
        }
    
    def verify_transaction(self, key_id: str, signed_data: dict) -> bool:
        import json
        message = json.dumps(signed_data["transaction"], sort_keys=True).encode()
        signature = bytes.fromhex(signed_data["signature"])
        return self._provider.verify(message, signature, self._keys[key_id]["public"])


# ── 使用例:アルゴリズムを切り替えてもAPIは同じ ──

# 従来のRSA
rsa_service = CryptoAgileService(RSAProvider())
rsa_service.setup_keys("user_001")

# 量子耐性のML-DSA(コードの変更は最小限)
pqc_service = CryptoAgileService(MLDSAProvider("ML-DSA-65"))
pqc_service.setup_keys("user_001")

transaction = {"from": "A", "to": "B", "amount": 50000, "ts": "2026-04-14"}

for label, service in [("RSA-2048", rsa_service), ("ML-DSA-65", pqc_service)]:
    signed = service.sign_transaction("user_001", transaction)
    verified = service.verify_transaction("user_001", signed)
    print(f"[{label}] 署名・検証: {verified}")

6-2. ハイブリッドモード(移行期間中の推奨構成)

移行期間中は「古い暗号 + 新しいPQC」を並列で使うハイブリッド方式が安全です。

class HybridCryptoProvider(CryptoProvider):
    """
    RSA + ML-DSA のハイブリッド署名
    どちらかが破られても安全を維持する「二重防衛」
    """
    
    def __init__(self):
        self._rsa = RSAProvider()
        self._pqc = MLDSAProvider("ML-DSA-65")
    
    @property
    def algorithm_name(self) -> str:
        return "Hybrid-RSA2048+ML-DSA-65"
    
    def generate_keypair(self) -> Tuple[bytes, bytes]:
        rsa_pub, rsa_priv = self._rsa.generate_keypair()
        pqc_pub, pqc_priv = self._pqc.generate_keypair()
        import struct
        # 両方の鍵を連結して保存(実際はより堅牢な構造化が必要)
        combined_pub = struct.pack(">I", len(rsa_pub)) + rsa_pub + pqc_pub
        combined_priv = struct.pack(">I", len(rsa_priv)) + rsa_priv + pqc_priv
        return combined_pub, combined_priv
    
    def _split_keys(self, combined: bytes):
        import struct
        length = struct.unpack(">I", combined[:4])[0]
        key1 = combined[4:4+length]
        key2 = combined[4+length:]
        return key1, key2
    
    def sign(self, message: bytes, private_key: bytes) -> bytes:
        rsa_priv, pqc_priv = self._split_keys(private_key)
        rsa_sig = self._rsa.sign(message, rsa_priv)
        pqc_sig = self._pqc.sign(message, pqc_priv)
        import struct
        return struct.pack(">I", len(rsa_sig)) + rsa_sig + pqc_sig
    
    def verify(self, message: bytes, signature: bytes, public_key: bytes) -> bool:
        import struct
        rsa_pub, pqc_pub = self._split_keys(public_key)
        sig_len = struct.unpack(">I", signature[:4])[0]
        rsa_sig = signature[4:4+sig_len]
        pqc_sig = signature[4+sig_len:]
        # 両方の署名が正当な場合のみ有効
        return (self._rsa.verify(message, rsa_sig, rsa_pub) and
                self._pqc.verify(message, pqc_sig, pqc_pub))

7. 既存システムのPQC脆弱性スキャン

自社システムが量子脆弱な暗号を使っているか診断するスクリプトです。

import ssl
import socket
import subprocess
import json
from typing import List, Dict

QUANTUM_VULNERABLE_ALGORITHMS = {
    "key_exchange": ["RSA", "DH", "ECDH", "ECDSA"],
    "signature": ["RSA", "DSA", "ECDSA"],
}

QUANTUM_SAFE_ALGORITHMS = {
    "key_exchange": ["ML-KEM", "Kyber", "X25519Kyber768"],
    "signature": ["ML-DSA", "SLH-DSA", "Dilithium"],
}

def check_tls_certificate(hostname: str, port: int = 443) -> Dict:
    """TLS証明書の暗号アルゴリズムを診断"""
    result = {
        "hostname": hostname,
        "port": port,
        "issues": [],
        "pqc_ready": False
    }
    
    try:
        context = ssl.create_default_context()
        with socket.create_connection((hostname, port), timeout=5) as sock:
            with context.wrap_socket(sock, server_hostname=hostname) as ssock:
                cert = ssock.getpeercert()
                cipher = ssock.cipher()
                
                result["cipher_suite"] = cipher[0] if cipher else "Unknown"
                result["tls_version"] = ssock.version()
                
                # 脆弱なアルゴリズムのチェック
                cipher_name = cipher[0] if cipher else ""
                for vulnerable_alg in QUANTUM_VULNERABLE_ALGORITHMS["key_exchange"]:
                    if vulnerable_alg in cipher_name.upper():
                        result["issues"].append(
                            f"⚠️  量子脆弱な鍵交換アルゴリズムを検出: {vulnerable_alg}"
                        )
                
                # PQC対応チェック
                for safe_alg in QUANTUM_SAFE_ALGORITHMS["key_exchange"]:
                    if safe_alg.upper() in cipher_name.upper():
                        result["pqc_ready"] = True
                        break
                
    except Exception as e:
        result["error"] = str(e)
    
    return result


def scan_endpoints(hosts: List[str]) -> None:
    """複数のエンドポイントをスキャン"""
    print("=" * 60)
    print("PQC脆弱性スキャン レポート")
    print("=" * 60)
    
    for host in hosts:
        result = check_tls_certificate(host)
        status = "✅ PQC対応済み" if result.get("pqc_ready") else "❌ PQC未対応"
        
        print(f"\n{host}")
        print(f"  TLSバージョン: {result.get('tls_version', 'N/A')}")
        print(f"  暗号スイート: {result.get('cipher_suite', 'N/A')}")
        print(f"  量子耐性: {status}")
        
        for issue in result.get("issues", []):
            print(f"  {issue}")
        
        if result.get("error"):
            print(f"  エラー: {result['error']}")

# 使用例(自社APIサーバーなどを指定)
# scan_endpoints(["your-api.example.com", "payment.example.com"])
scan_endpoints(["example.com"])

8. AIを使った異常検知(HNDL攻撃の兆候を検出)

大量データを収集・保存する不審なアクセスパターンを機械学習で検出します。

pip install scikit-learn pandas numpy
import numpy as np
import pandas as pd
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler

# ネットワークトラフィックの特徴量(実際はログから生成)
def generate_sample_traffic_data():
    np.random.seed(42)
    n_normal = 1000
    n_anomaly = 50
    
    # 通常トラフィック
    normal = pd.DataFrame({
        "bytes_transferred": np.random.normal(5000, 1000, n_normal),    # 転送量(bytes)
        "session_duration": np.random.normal(30, 10, n_normal),         # セッション時間(秒)
        "request_interval": np.random.normal(2, 0.5, n_normal),         # リクエスト間隔(秒)
        "unique_endpoints": np.random.randint(1, 5, n_normal),          # アクセス先の数
        "encrypted_payload_ratio": np.random.normal(0.6, 0.1, n_normal) # 暗号化比率
    })
    
    # HNDL攻撃的な異常トラフィック(大量データを静かに収集)
    anomaly = pd.DataFrame({
        "bytes_transferred": np.random.normal(500000, 50000, n_anomaly), # 異常に大量
        "session_duration": np.random.normal(3600, 600, n_anomaly),      # 長時間継続
        "request_interval": np.random.normal(0.1, 0.05, n_anomaly),     # 高頻度
        "unique_endpoints": np.random.randint(10, 50, n_anomaly),        # 広範囲スキャン
        "encrypted_payload_ratio": np.random.normal(0.99, 0.005, n_anomaly) # 完全暗号化
    })
    
    return normal, anomaly

# モデルの学習と検出
normal_data, anomaly_data = generate_sample_traffic_data()

# 正常データで学習(教師なし学習)
scaler = StandardScaler()
X_train = scaler.fit_transform(normal_data)

model = IsolationForest(
    contamination=0.05,  # 異常の割合の推定値
    random_state=42,
    n_estimators=200
)
model.fit(X_train)

# 検出テスト
test_data = pd.concat([normal_data.sample(100), anomaly_data], ignore_index=True)
X_test = scaler.transform(test_data)
predictions = model.predict(X_test)  # 1: 正常、-1: 異常

anomaly_indices = np.where(predictions == -1)[0]
print(f"検出された異常セッション数: {len(anomaly_indices)}")
print(f"異常スコア(上位5件):")

scores = model.score_samples(X_test)
top_anomalies = np.argsort(scores)[:5]
for idx in top_anomalies:
    print(f"  インデックス {idx}: スコア={scores[idx]:.3f}, "
          f"転送量={test_data.iloc[idx]['bytes_transferred']:.0f} bytes")

9. QKD(量子鍵配送)のシミュレーション

物理的に盗聴が検出可能な量子通信の仕組みを、BB84プロトコルでシミュレーションします。

pip install numpy qiskit qiskit-aer
import numpy as np
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator

def bb84_protocol_simulation(num_bits: int = 20, eavesdrop: bool = False):
    """
    BB84量子鍵配送プロトコルのシミュレーション
    
    Args:
        num_bits: 送信するビット数
        eavesdrop: 盗聴者(Eve)を含めるか
    """
    # ── Alice(送信者)──
    # ランダムなビット列と測定基底を生成
    alice_bits = np.random.randint(0, 2, num_bits)
    alice_bases = np.random.randint(0, 2, num_bits)  # 0: Z基底, 1: X基底
    
    # ── 量子チャネルでの送信 ──
    transmitted_states = []
    for i in range(num_bits):
        qc = QuantumCircuit(1, 1)
        
        # ビット値に応じて状態を準備
        if alice_bits[i] == 1:
            qc.x(0)  # |1⟩
        if alice_bases[i] == 1:
            qc.h(0)  # X基底(|+⟩または|-⟩)
        
        # 盗聴者Eveの介入
        if eavesdrop:
            eve_basis = np.random.randint(0, 2)
            if eve_basis == 1:
                qc.h(0)
            qc.measure(0, 0)  # 測定→状態が崩壊
            qc.reset(0)
            if eve_basis == 1:
                qc.h(0)
        
        transmitted_states.append(qc)
    
    # ── Bob(受信者)の測定 ──
    bob_bases = np.random.randint(0, 2, num_bits)
    bob_results = []
    
    simulator = AerSimulator()
    for i, qc in enumerate(transmitted_states):
        measure_qc = qc.copy()
        if bob_bases[i] == 1:
            measure_qc.h(0)
        measure_qc.measure(0, 0)
        
        result = simulator.run(measure_qc, shots=1).result()
        bit = int(list(result.get_counts().keys())[0])
        bob_results.append(bit)
    
    # ── 基底の照合(公開チャネルで行う) ──
    sifted_key_alice = []
    sifted_key_bob = []
    
    for i in range(num_bits):
        if alice_bases[i] == bob_bases[i]:  # 同じ基底を使ったビットのみ採用
            sifted_key_alice.append(alice_bits[i])
            sifted_key_bob.append(bob_results[i])
    
    # エラー率の計算(盗聴があれば高くなる)
    if len(sifted_key_alice) > 0:
        errors = sum(a != b for a, b in zip(sifted_key_alice, sifted_key_bob))
        error_rate = errors / len(sifted_key_alice)
    else:
        error_rate = 0
    
    print(f"=== BB84プロトコル シミュレーション ===")
    print(f"送信ビット数: {num_bits}")
    print(f"盗聴あり: {eavesdrop}")
    print(f"鍵ビット数(基底一致): {len(sifted_key_alice)}")
    print(f"エラー率: {error_rate:.1%}")
    
    # 判定(エラー率11%以上は盗聴の強い兆候)
    if error_rate > 0.11:
        print(f"🚨 警告: エラー率が高すぎます。盗聴の可能性があります!")
        print(f"→ このセッションを破棄し、新しい鍵交換を実施してください。")
    else:
        print(f"✅ 安全: 通信チャネルは盗聴されていません。")
    
    return sifted_key_alice, error_rate

# 正常通信
print("【正常通信】")
key, err = bb84_protocol_simulation(num_bits=50, eavesdrop=False)

print("\n【盗聴あり】")
key_eve, err_eve = bb84_protocol_simulation(num_bits=50, eavesdrop=True)

10. PQC移行のロードマップ(実装フェーズ別)

自社システムへの適用手順

Phase 1:現状把握(今すぐ実施)
├── 使用中の暗号アルゴリズムを棚卸し(上記スキャンスクリプトを活用)
├── 長期保存データの特定(10年以上保存が必要なもの)
└── ベンダー・ライブラリのPQC対応状況確認

Phase 2:ハイブリッド移行(1〜2年)
├── 暗号アジリティアーキテクチャの導入
├── 新規システムにML-KEM/ML-DSAを実装
└── 既存システムにハイブリッドモードを適用

Phase 3:完全PQC移行(3〜5年)
├── レガシー暗号(RSA/ECC)の段階的廃止
├── TLS 1.3 + PQC拡張への対応
└── NIST標準準拠の第三者認証を取得

Phase 4:継続的監視(5年以上)
├── 量子コンピュータの進化速度を継続モニタリング
└── 新たな脆弱性発見時の迅速なアルゴリズム差し替え

主要ライブラリのPQC対応状況(2026年4月時点)

ライブラリ / 言語 PQC対応 参考リンク
OpenSSL 3.x + OQS Provider ✅ 対応 oqs-provider
Python oqs ✅ 対応 oqs-python
Go circl (Cloudflare) ✅ 対応 circl
Java (Bouncy Castle) ✅ 対応 bouncycastle.org
Rust pqcrypto ✅ 対応 crates.io
Node.js ⚠️ サードパーティ経由 node-oqs など

まとめ

対策技術 役割 実装の優先度
ML-KEM(Kyber) 鍵交換の量子耐性化 🔴 最優先(TLS・API通信)
ML-DSA(Dilithium) 署名の量子耐性化 🔴 最優先(認証・取引署名)
ハイブリッドモード 移行期間の二重防衛 🟠 高優先(今すぐ検討)
暗号アジリティ 将来の差し替えを容易に 🟠 高優先(新規設計時に必須)
HNDL異常検知(AI) 今の攻撃を検出 🟡 中優先(セキュリティ強化)
QKD 物理法則による盗聴検出 🟢 長期(インフラ更新時)

「量子コンピュータが脅威になるのはまだ先」という認識は危険です。HNDL攻撃は今この瞬間にも進行している可能性があります。まず自社システムの暗号棚卸しと、新規開発への暗号アジリティ導入から始めましょう。


参考資料・公式リソース


元記事あなたの銀行口座は「量子コンピュータ」に丸裸にされる——金融インフラが直面する史上最大の脅威と、その防衛技術|AI Robotics Quantum Lab

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?