ML-DSA と SLH-DSA のどちらを使うかは、NIST が標準化したポスト量子署名の中での主要な選択肢であり、どちらも 2024年8月13日に公開されました。ML-DSA(FIPS 204、CRYSTALS-Dilithium に由来)は構造化格子に依拠し、SLH-DSA(FIPS 205、SPHINCS+ に由来)はハッシュ関数の安全性だけに依拠します。サイズと速度の特性が大きく異なるため、ほとんどのシステムは ML-DSA を使い、保守的な前提がコストに見合う場面で SLH-DSA を使うことになるでしょう。
比較表
| ML-DSA(FIPS 204) | SLH-DSA(FIPS 205) | |
|---|---|---|
| 安全性の前提 | Module-LWE と Module-SIS の格子問題 | SHA-2 または SHAKE の性質のみ |
| パラメーターセット | ML-DSA-44、-65、-87 | 12 セット:SHA2 または SHAKE × 128/192/256 × s(small)または f(fast) |
| セキュリティカテゴリ | 2、3、5 | 1、3、5 |
| 公開鍵 | 1,312 / 1,952 / 2,592 バイト | 32 / 48 / 64 バイト |
| 署名 | 2,420 / 3,309 / 4,627 バイト | 7,856 バイト(128s)〜49,856 バイト(256f) |
| 秘密鍵 | 展開形式で 2,560〜4,896 バイト、または 32 バイトのシード | 64 / 96 / 128 バイト |
| 毎秒の署名回数(OpenSSL 3.6.5) | 約 3,900(44)、2,400(65)、2,050(87) | 約 7(SHA2-128s)、144(SHA2-128f)、3.5(SHA2-192s) |
| 毎秒の検証回数 | 約 20,800(44)、13,600(65)、8,500(87) | 約 7,400(SHA2-128s)、2,400(SHA2-128f) |
| 毎秒の鍵生成回数 | 約 22,000(44) | 約 55(128s)、3,400(128f) |
| 署名時の乱数 | デフォルトはヘッジ付き、決定的なバリアントも可 | デフォルトはヘッジ付き、決定的なバリアントも可 |
| コンテキスト文字列 | 最大 255 バイト | 最大 255 バイト |
| 事前ハッシュ版 | HashML-DSA(§5.4) | HashSLH-DSA(§10.2.2) |
| X.509 | RFC 9881(id-ml-dsa-44 = 2.16.840.1.101.3.4.3.17 …) | RFC 9909(id-slh-dsa-sha2-128s = …3.4.3.20 …) |
速度は Apple M4 Max の 1 コアで openssl speed を使って計測しました。OpenSSL の ML-DSA はポータブルな C 実装で、最適化された実装では署名が数倍高速になります。
安全性の前提
ML-DSA は、Fiat–Shamir with Aborts に基づく格子ベースの署名方式です。安全性は Module-LWE(加群上の誤差付き学習)問題と Module-SIS(加群上の短整数解)問題に基づいています。これらの問題は 20 年ほど研究され、古典攻撃と量子攻撃のどちらにも耐えてきましたが、格子基底簡約の手法が進歩するにつれて、具体的な安全性の見積もりは今も変動しています。NIST は、それらの見積もりに対して余裕を持たせたパラメーターセットを選びました。
SLH-DSA は、ハイパーツリー状に配置したワンタイム署名とフュータイム署名(いずれもハッシュベース署名)から署名を構成します。SHA-256 や SHAKE256 が原像計算困難性とそれに関連する性質を保っている限り、SLH-DSA は安全です。攻撃の対象となる代数的な構造がないからです。そのため SLH-DSA は NIST が標準化した中で最も保守的な署名であり、格子暗号に対する攻撃に飛躍的な進展があった場合の自然な備えになります。ステートフルなハッシュベース署名方式である LMS や XMSS とは異なり、状態を保持する必要はなく、各鍵で最大 2⁶⁴ 個のメッセージに署名できます。
実際のサイズと速度
次のスクリプトは、OpenSSL 3.6.5 を使い、各アルゴリズムで同じメッセージに署名します。
#!/bin/sh
dir=$(mktemp -d)
cd "$dir" || exit 1
printf 'firmware-2026.10.bin digest' > msg
for alg in ML-DSA-44 ML-DSA-65 SLH-DSA-SHA2-128s SLH-DSA-SHA2-128f ED25519; do
openssl genpkey -algorithm "$alg" -out key.pem 2>/dev/null
openssl pkeyutl -sign -rawin -inkey key.pem -in msg -out sig.bin 2>/dev/null
openssl pkey -in key.pem -pubout -outform DER -out pub.der 2>/dev/null
openssl pkey -in key.pem -pubout -out pub.pem 2>/dev/null
if openssl pkeyutl -verify -rawin -pubin -inkey pub.pem -in msg -sigfile sig.bin >/dev/null 2>&1; then ok=yes; else ok=no; fi
printf '%-18s public key (SPKI DER) %5s bytes, signature %6s bytes, verifies: %s\n' "$alg" \
"$(wc -c < pub.der | tr -d ' ')" "$(wc -c < sig.bin | tr -d ' ')" "$ok"
done
cd / && rm -rf "$dir"
ML-DSA-44 public key (SPKI DER) 1334 bytes, signature 2420 bytes, verifies: yes
ML-DSA-65 public key (SPKI DER) 1974 bytes, signature 3309 bytes, verifies: yes
SLH-DSA-SHA2-128s public key (SPKI DER) 50 bytes, signature 7856 bytes, verifies: yes
SLH-DSA-SHA2-128f public key (SPKI DER) 50 bytes, signature 17088 bytes, verifies: yes
ED25519 public key (SPKI DER) 44 bytes, signature 64 bytes, verifies: yes
両者の特性は正反対です。ML-DSA は公開鍵と署名がキロバイト単位で、毎秒数千回の署名ができます。SLH-DSA は公開鍵がごく小さい(Ed25519 と同程度)一方で署名は 8〜50 KB あり、小さい s のセットでは、このマシンで署名ごとに約 137 ms かかります(f のセットは、署名サイズが倍になる代わりに署名が約 20 倍速くなります)。検証はどちらも高速です。証明書チェーンや TLS ハンドシェイクでは ML-DSA は実用的ですが、SLH-DSA は実用的ではありません。一方、リリースのたびに一度だけ署名し、起動のたびに検証するファームウェアイメージでは、SLH-DSA のコストは問題にならず、ごく小さな公開鍵はブート ROM に収まります。
運用上の詳細
- ヘッジ付き署名:どちらの標準も、デフォルトでは新しい乱数と鍵から導出した値を混ぜ合わせ、乱数生成器を持たないプラットフォーム向けに決定的なバリアントも認めています。検証者には両者の違いを区別できません。
- コンテキスト:どちらも最大 255 バイトのコンテキスト文字列をすべての署名に結び付けます。プロトコルはこれを使って用途を分離すべきです。
- 通常版(pure)と事前ハッシュ版:HashML-DSA と HashSLH-DSA は、ハッシュ関数の OID を結び付けたうえでダイジェストに署名します。これらは別々の OID を持つ別のアルゴリズムであり、FIPS 204 は鍵をどちらか一方の方式だけに使うことを推奨しています。
- 秘密鍵の形式:ML-DSA の鍵は 32 バイトのシードとして保存でき、RFC 9881 は
seedまたはbothのエンコーディングでこれを認めています。一方が展開済みの鍵を想定していると、相互運用の問題が起こります。 - ハードウェアと FIPS 認証:ML-DSA と SLH-DSA を搭載した認証済みモジュールは 2024年以降に登場しています。対応する正確なパラメーターセットは、モジュールの証明書で確認してください。
どちらを選ぶべきか
- プライベート PKI、内部の mTLS、文書署名とコード署名:ML-DSA-65(または 44)を使います。
- ファームウェア、セキュアブート、ハードウェアの信頼の基点:SLH-DSA-128s または 192s を使います。署名者の状態を管理できるなら、CNSA 2.0 がこの用途に義務付けているステートフルな LMS や XMSS も使えます。
- 数十年にわたって使う長期アーカイブとルート証明書:SLH-DSA を使います。ML-DSA と併用して二重署名にすることも考えられます。
- 大量の署名(トークン、トランザクション、ログ):ML-DSA を使います。SLH-DSA では処理が追いつきません。
- 帯域の限られたプロトコル:どちらも小さくはありません。現時点で標準化済みの選択肢として最も小さいのは ML-DSA-44 で、FN-DSA(FIPS 206 ドラフト)はさらに小さいサイズを目指しています。
- 公開 WebPKI の TLS:現時点ではどちらもブラウザーに受け入れられていません。移行の全体像は ML-DSA と ECDSA の比較を参照してください。
移行時の注意点
- 署名の用途を有効期間と量で棚卸しする:長期間使われ、署名の頻度が低いアーティファクトは SLH-DSA の候補で、それ以外はすべて ML-DSA です。
- 最終版の標準を実装したライブラリのバージョンを選ぶ:OpenSSL 3.5 以降(2025年4月)、Java 版 Bouncy Castle 1.79 以降(標準化された秘密鍵のエンコーディングには 1.81 以降)、ML-DSA には Go 1.27 の
crypto/mldsaを使います。標準化前の Dilithium や SPHINCS+ の出力とは互換性がありません。 - サイズを考慮して計画する:証明書、トークン、署名のフィールドの上限を引き上げます。ML-DSA-65 の証明書は約 5.5 KB(姉妹編の比較記事を参照)で、SLH-DSA の署名は一般的なヘッダーやレコードの上限を超えることがあります。
- 移行期間中はハイブリッドを検討する:ML-DSA と ECDSA または EdDSA を組み合わせた複合署名の証明書(IETF のドラフト)や二重署名を使えば、従来の検証者も引き続き動作します。
- コンテキスト文字列とバリアント(通常版か事前ハッシュ版か)をプロトコル仕様で固定します。そうすれば、すべての実装で設定が一致します。