アルゴリズムレジストリ
ハッシュ、AEAD、KEM、KDF、署名を識別する名前付きレジストリと、ポスト量子への移行を破壊的ではなく追加的なものにする俊敏性ルールについて。
Label 309 における暗号方式の選択は、すべて拡張可能なレジストリから引いた文字列識別子で名前付けされます。たとえば sha2-256、chacha20-poly1305-stream64k、EdDSA などです。レコードが生のアルゴリズム番号や暗黙の前提を抱え込むことはありません。どのプリミティブを使ったかを明示し、検証者はその識別子を引いて照合します。これがアルゴリズム俊敏性(アルゴリズム非依存・差し替え可能)という不変条件を支える仕組みです。レジストリは時とともに拡張でき、自分が実装していない識別子に出会った検証者は、安定した型付きエラーでレコードを拒否します。クラッシュすることはなく、検証できないものを黙って受け入れることもありません。
このたった一つのルールが、ポスト量子アルゴリズムへの移行を追加的なものにします。新しい識別子はテーブルに行が一つ増えるだけのことであって、ワイヤーフォーマットの新しいバージョンではありません。古いレコードはこれまでとまったく同じように検証され続け、古い検証者は理解できるように作られていないレコードに対して安全側に倒れて拒否します。
二つの恒久ルール
どのレジストリにも共通して、絶対に譲れない二つの制約があります。実装は独自の暗号方式を考案してはなりません(MUST NOT)。すべてのプリミティブは、名前の付いた公開標準にたどれます。そしてすべての暗号化は認証付きでなければなりません(MUST)。許可されるのは AEAD 構成のみであり、後付けの(あるいは欠落した)完全性チェックを伴う非認証の暗号は決して認められません。
ハッシュ
コンテンツのハッシュ値はあらゆるレコードの主たる主張であるため、ハッシュレジストリは最も中核的な役割を担います。登録された二つの関数はいずれも 32 バイトのダイジェストを生成し、適合実装はその両方をサポートすることが必須です。
| 識別子 | アルゴリズム | ダイジェスト |
|---|---|---|
sha2-256 | SHA-256 (FIPS 180-4) | 32 B |
blake2b-256 | BLAKE2b-256 (RFC 7693) | 32 B |
生成者は多層防御のため、同じコンテンツを両方の関数でハッシュ化してもかまいません(MAY)。有効なレコードには一つのハッシュ値があれば十分です。
Merkle コミットメント
順序付けられたリーフのリストを単一のオンチェーンルートにコミットするために、Label 309 は Merkle コミットメントの識別子を一つ登録しています。これは SHA-256 二分 Merkle 木に対して IANA に登録された文字列であり、リーフとノードの衝突を防ぐドメイン分離、すなわちリーフ接頭辞(0x00)と内部ノード接頭辞(0x01)を共有します。
| 識別子 | アルゴリズム | ルート |
|---|---|---|
rfc9162-sha256 | RFC 9162 二分 Merkle 木、SHA-256 | 32 B |
リーフが一つだけの木は、生のリーフではなく SHA-256(0x00 ‖ leaf) にコミットします。したがって単一ファイルの証明は、1 リーフの木ではなく必ずプレーンなハッシュ識別子を使わなければなりません(MUST)。
AEAD
AEAD レジストリは、ワイヤー上で封緘済みペイロードをどのコンテンツフォーマットが保護するか、すなわち enc.aead フィールドを定めます。enc.scheme: 1 の下にはちょうど一つの識別子が登録されており、それは single-shot の暗号ではなくセグメント化されたフォーマットです。
| 識別子 | アルゴリズム | 鍵 / ノンス / チャンクごとのノンス / タグ | ステータス |
|---|---|---|---|
chacha20-poly1305-stream64k | ChaCha20-Poly1305、64 KiB セグメント化 STREAM | 32 B / 24 B / チャンクごと 12 B / 16 B | 必須 — ワイヤーフォーマット |
aes-256-gcm | AES-256-GCM | — | 予約済み(将来のプロファイル用) |
chacha20-poly1305-stream64k は、age v1 仕様の 64 KiB セグメント化 STREAM レイアウトにした ChaCha20-Poly1305(RFC 8439)です。平文は 65536 バイトのチャンクに分割され、各チャンクはコンテンツ鍵のもと、12 バイトのチャンクごとのノンス uint88_be(counter) ‖ final_flag(counter は 0 から、final_flag は最後のチャンクで 0x01)と空のチャンクごとの AAD で封緘され、チャンクごとに 16 バイトのタグを生成します。24 バイトの enc.nonce はチャンクのノンスではありません。それはコンテンツ鍵の HKDF のエンベロープごとに一意なソルトであり、これこそがカウンターのノンスを安全に保つものです。コンテンツ鍵は一度しか使われないため、2 つのストリームが (key, nonce) の組を共有することは決してなく、状態を持たないプロデューサーがエンベロープをまたいでノンスを調整することもありません。セグメント化されたレイアウトにより、検証者は大きなペイロードを限られたメモリで逐次的に認証し放出でき、ファイナルフラグによって切り詰めが検知可能になります。ワイヤー上の綴りはちょうど chacha20-poly1305-stream64k です。別の綴りを生成してはなりません(MUST NOT)。完全な構成は 封緘済み PoE にあります。
ワイヤー上のコンテンツフォーマットとして現れてよい識別子は chacha20-poly1305-stream64k だけです。別の構成 chacha20-poly1305(RFC 8439、32 バイト鍵 / 12 バイトノンス / 16 バイトタグ)は、封緘構成の内部で受信者ごとの鍵をラップするために使われます。すなわち、12 バイトの全ゼロノンス、選択した KEM の info ラベルに設定された AAD で、48 バイトの wrap(32 バイトのラップ済み鍵 + 16 バイトのタグ)を生成します。これは構成要素であってワイヤー識別子ではないため、これを enc.aead に指定したレコードは拒否しなければなりません(MUST)。aes-256-gcm は名前こそ付いていますが無効です。将来の暗号化プロファイル(enc.scheme: 2)向けに予約されており、v1 の検証者はこれを選択したレコードをすべて拒否します。
KEM
KEM レジストリは、封緘済みペイロードを特定の受信者宛にするために使う鍵カプセル化メカニズムを扱います。Label 309 は古典的な曲線ベースの KEM と、最初のリリースから有効なポスト量子ハイブリッドを登録しています。
| 識別子 | アルゴリズム | 公開鍵 / 秘密鍵 | 暗号文 / 共有秘密 |
|---|---|---|---|
x25519 | X25519 ECDH (RFC 7748) | 32 B / 32 B | 32 B / 32 B |
mlkem768x25519 | X-Wing ハイブリッド(ML-KEM-768 + X25519) | 1216 B / 32 B | 1120 B / 32 B |
mlkem768x25519 は draft-connolly-cfrg-xwing-kem-10 に基づく X-Wing 構成です。ML-KEM-768(FIPS 203)と X25519(RFC 7748)を組み合わせており、攻撃者が共有秘密を復元するには両方を破る必要があります。公開鍵は ML-KEM-768 のカプセル化鍵に X25519 公開鍵を連結したもの(1184 B ‖ 32 B = 1216 B)で、秘密は完全な鍵を導出するための 32 バイトのシードです。各受信者の暗号文は、ML-KEM-768 の暗号文に一時的な X25519 公開鍵を連結したもの(1088 B ‖ 32 B = 1120 B)であり、二つの共有秘密を X-Wing の SHA3-256 コンバイナー(FIPS 202)で結合して最終的な 32 バイトの秘密を得ます。Label 309 は X-Wing をブラックボックスの KEM として消費し、カプセル化・脱カプセル化・32 バイトの共有秘密だけを使い、コンバイナー内部のハッシュのいかなる性質にも依拠しません。識別子は、確立された X-Wing の綴りに合わせて内部にハイフンを入れずに記述します。
このハイブリッドは、コンテンツ AEAD とは独立して、暗号化ヘッダーによってレコードごとに選択されます。すでに登録済みであるため、ポスト量子の秘匿性はワイヤーフォーマットの新バージョンを待つことではなく、識別子を選ぶだけのことになります。
1 つのレコードはちょうど 1 つの enc.kem を指定し、すべてのスロットがその KEM の形を使います。形の異なるスロットは ENC_SLOT_INVALID_SHAPE、長さの誤った epk(≠ 32 B)または kem_ct(≠ 1120 B)は KEM_EPK_LENGTH_MISMATCH / KEM_CT_LENGTH_MISMATCH、未登録の enc.kem は UNSUPPORTED_KEM_ALG になります。カプセル化材料はさらに、1 つの slots[] の中で互いに異なっていなければなりません。すべての epk 値(x25519 の場合)またはすべての kem_ct 値(mlkem768x25519 の場合)が異なっていなければなりません(MUST)。レコード内の重複は、いかなる KEM や AEAD のプリミティブが走る前に、ENC_SLOTS_DUPLICATE_KEM_MATERIAL で拒否されます。epk または kem_ct の重複は、全ゼロノンスのラップが依拠するスロットごとの鍵の一意性を壊すからです。検証者はさらに、いかなるプリミティブよりも前にパーサのリソース使用を制限します。slots[] が参照上限の 1024 スロットを超える封筒は ENC_SLOTS_TOO_MANY、デコード後の enc 封筒が 65 536 バイトを超えるものは ENC_ENVELOPE_TOO_LARGE になります。いずれの上限も、正直なレコードに上限を課す約 16 KiB の Cardano メタデータ天井をはるかに上回ります。これらはワイヤーフィールドではなく、検証者が強制するデプロイ固定の定数であり、デプロイ側でより厳しくしてもかまいません(MAY)。
KDF
KDF レジストリは鍵導出関数に名前を付けます。hkdf-sha256 は封緘構成の内部で鍵を導出し、argon2id は総当たり攻撃に抗してパスフレーズを伸長させ、必須のパラメータ下限を備えます。
| 識別子 | アルゴリズム | パラメータ |
|---|---|---|
hkdf-sha256 | HKDF-SHA-256 (RFC 5869) | salt(任意)、info(任意)、出力長 |
argon2id | Argon2id (RFC 9106) | メモリ ≥ 65536 KiB、反復回数 ≥ 3、並列度 ≥ 1 |
Argon2id の下限は規範的です。パスフレーズで保護されたペイロードは、最低 64 MiB のメモリ、最低 3 回の反復、最低 1 レーンを使わなければなりません(MUST)。生成者はより強いパラメータを選んでもかまいませんし(MAY)、それらは検証者が導出を再現できるようレコードとともに運ばれます。プラットフォームが対応しているなら、生成者は並列度 p = 4 を設定すべきです(SHOULD)。これは RFC 9106 §4 の 2 番目の推奨プロファイルです。一方、検証者はデプロイの上限に従ったうえで、p ≥ 1 のいずれの値を受け入れてもかまいません(MAY)。これらの上限は実装上の MAY ではなく SHOULD です。検証者は、不合理なパラメータによる検証者側のサービス拒否を防ぐため、上限を強制すべきであり(SHOULD)、ENC_PASSPHRASE_PARAMS_EXCEED_POLICY を報告します。この上限はハードウェア依存かつ非規範的であり、下限コード ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW と混同してはなりません(MUST NOT)。
ワイヤーで選択できるのは argon2id だけです。レコードが enc.passphrase.alg に指定してよい唯一の識別子です。hkdf-sha256 は内部の構成要素であり、シード → 鍵の導出、スロットごとの KEK 導出、スロット集合の MAC 鍵、パスフレーズコミットメントの MAC 鍵、そしてコンテンツ鍵の導出の背後にある、固定の抽出・展開ステップです。ワイヤー識別子は持ちません。enc.passphrase.alg に hkdf-sha256 を指定したレコードは拒否しなければなりません(MUST)。HKDF は高エントロピーの入力のために作られたものであり、低エントロピーのパスフレーズを伸長するためのものではありません。
内部ラベルは定数であり、ワイヤーには載らない
封緘構成は、固定されたラベルリテラルの集合からドメイン分離を引き出します。HKDF の info タグと SHA-256 のプレフィックス(KEK ソルトのプレフィックス、トランスクリプトのプレフィックス、そしてアイテムハッシュのプレフィックス)です。いずれも enc.scheme: 1 の定数であり、終端文字も長さプレフィックスも持たない厳密な ASCII です。どれもシリアライズされることはなく、いかなるレジストリを通じても選択できません。全部で 11 あります。
| ラベル | 役割 |
|---|---|
cardano-poe-kek-v1 | x25519 パスのスロットごとの KEK の HKDF info |
cardano-poe-kek-mlkem768x25519-v1 | mlkem768x25519 パスのスロットごとの KEK の HKDF info |
cardano-poe-x25519-kek-salt-v1 | x25519 の KEK の HKDF salt のための SHA-256 プレフィックス |
cardano-poe-xwing-kek-salt-v1 | mlkem768x25519 の KEK の HKDF salt のための SHA-256 プレフィックス |
cardano-poe-item-hashes-v1 | アイテムハッシュのダイジェスト hashes_hash のための SHA-256 プレフィックス |
cardano-poe-slots-transcript-v1 | スロットトランスクリプトのハッシュ slots_hash のための SHA-256 プレフィックス |
cardano-poe-slots-mac-v1 | スロット集合の MAC 鍵の HKDF info |
cardano-poe-passphrase-transcript-v1 | パスフレーズトランスクリプトのハッシュ pw_hash のための SHA-256 プレフィックス |
cardano-poe-passphrase-mac-v1 | パスフレーズコミットメントの MAC 鍵の HKDF info |
cardano-poe-payload-v1 | slots パスのコンテンツ鍵の HKDF info |
cardano-poe-payload-passphrase-v1 | passphrase パスのコンテンツ鍵の HKDF info |
どちらの KEK ソルトも、KEM ごとのラベルのもとで一つのラベル付きハッシュの形 SHA-256(label ‖ enc.nonce ‖ <スロットの KEM 素材> ‖ pub_R) を共有します。これらのラベルは、鍵 のシード導出 info 文字列とも、署名 のレコード署名ドメインプレフィックスとも区別されます。この集合は衝突がなくプレフィックスも重ならないため、レコードごとの封緘ラベルが長期鍵の導出ラベルと等しくなることも、そのバイトプレフィックスになることもなく、アイデンティティ鍵の導出とレコードごとの鍵ラップが衝突することはありません。検証者は各リテラルをバイト単位でそのまま使わなければなりません(MUST)。1 バイトでも違えば、正直なプロデューサーには再現できない slots_mac、コミットメント、または AEAD タグになります。各ラベルを消費するバイトレベルの構成は 封緘済み PoE にあります。
署名
Label 309 は署名アルゴリズムを一つ登録しています。著作者性の署名は常に任意ですが、存在する場合は Ed25519 を用いた COSE_Sign1(RFC 9052)として運ばれます。
| 識別子 | COSE alg | アルゴリズム | ラッパー |
|---|---|---|---|
EdDSA | -8 | Ed25519 (RFC 8032) | COSE_Sign1 (RFC 9052) |
検証は RFC 8032 §5.1.7 に従って厳格です。実装は、非正規な署名エンコーディングと低位数の点を拒否しなければなりません(MUST。コファクター除去の拡張は行いません)。これは Cardano のウォレット全般で用いられる保守的な受容基準と一致するため、ある適合実装で検証が通る署名は、そのすべてで検証が通ります。
署名のサポートはコンテンツの主張とは独立しています。レコードの署名アルゴリズムを実装していない検証者は、その署名スロットを未サポートと印付けし、タイムスタンプとコンテンツの主張は完全に有効なまま残します。未知の署名アルゴリズムがレコードそのものを無効にすることは決してありません。
予約済み識別子
いくつかの識別子は名前が付いているものの、まだ有効ではありません。これらは合意済みの移行経路を示すもので、将来のプロファイルが場当たり的な文字列ではなく、安定した事前合意済みの名前を使えるようにします。適合する生成者はこれらを出力してはならず(MUST NOT)、適合する検証者はそのいずれかを使ったレコードを、対応する型付きエラーで拒否しなければなりません(MUST)。
| 識別子 | アルゴリズム | 役割 |
|---|---|---|
aes-256-gcm | AES-256-GCM (NIST SP 800-38D) | コンテンツ AEAD |
ml-kem-768 | ML-KEM-768 (FIPS 203)、単体 | KEM |
ml-dsa-65 | ML-DSA (FIPS 204) | 署名 |
slh-dsa-sha2-128s | SLH-DSA (FIPS 205) | 署名 |
ml-kem-768 は単体のポスト量子 KEM であり、登録済みのハイブリッド mlkem768x25519 とは別物です。Label 309 が提供するのはハイブリッドのほうで、ポスト量子の半分が加わった後も古典的なフォールバックを残しておくべきだという原則に基づいています。
アルゴリズム俊敏性と移行
アルゴリズムの追加は、それ自体で完結する追加的な操作です。プリミティブについて公開標準を引用し、識別子を適切なレジストリに加え、十分にレビューされた信頼できる実装を用意し、独立した実装どうしがバイト単位で一致することを保証する言語横断の適合フィクスチャを公開します。スキーマが変わらないため、ワイヤーフォーマットのバージョンは変わりません。増えるのは認識される文字列の集合だけです。
その帰結は、レジストリの設計から直接導かれます。
- 古いレコードは検証可能なまま。 その識別子は依然としてレジストリにあるため、既存のレコードはすべて、発行された日とまったく同じように検証されます。
- 古い検証者は安全側に倒れる。 新しい識別子より前に作られた検証者は、それを使うレコードを推測で処理するのではなく、安定した
UNSUPPORTED_*エラーで拒否します。黙って受け入れる経路は存在しません。 - ポスト量子のサポートは追加的。
mlkem768x25519がすでに登録済みであり、新しい KEM や署名も同じ仕組みに収まるため、ポスト量子への移行はレジストリの拡張であって、破壊的な移行ではありません。
ワイヤーフォーマットのバージョンを上げるのは、本当に破壊的なスキーマ変更、すなわち必須フィールドの追加、フィールドの削除、型の変更に限られます。レジストリの拡張がこれに当たることは決してありません。だからこそ暗号方式のカタログは、発行済みの証明を取り残すことなく進化できるのです。