検証
Label 309 が定める3つの検証者ロール、判定結果の状態、確定の深さ、そして型付きエラーカタログ。だれもが公開インフラだけで同じ答えにたどり着く仕組みを解説します。
Label 309 は、主張するだけのものではなく、検証できるものです。発行者はコンテンツのハッシュ値を label 309 のもとで Cardano のチェーン上に記録します。その時点から、主張はそのバイト列だけで自立し、 トランザクション参照を持つ者はだれでも検証できます。このページでは、その検証が どのように 動くのか を定義します。3つの検証者ロール、それぞれが何に触れ何に触れないか、それらが出す判定結果の状態、判定が 暫定にとどまる確認深さの下限、そして同じ入力に対して2つの独立した実装が同じ失敗で一致するようにする 型付きエラーカタログです。
決定的な性質は サービス非依存 です。準拠する検証者は、公開チェーン、検証者自身が選んだ Cardano エクスプローラまたはゲートウェイ、そしてコンテンツや封緘済みの主張については同じく検証者が選んだ コンテンツアドレス指定ストレージのゲートウェイだけを使って判定にたどり着きます。発行者に問い合わせる ことは一切ありません。標準は特定のプロバイダーを指名しません。ゲートウェイは運用者が与える入力です。
3つのロール、それぞれが厳密な拡張
検証は層をなしています。各ロールは、その上位のロールが行うことをすべて行い、そこに能力を1つだけ追加 します。下位のロールはそれ単独で完全かつ有用な検証者です。証明できる範囲が狭いだけです。
| ロール | 追加すること | 触れる対象 |
|---|---|---|
| 構造バリデーター | レコードのバイト列に対するスキーマ+ドメイン適合性の確認 | 何にも触れない(純粋関数) |
| 公開検証者 | チェーン解決、オンチェーン包含、署名検証 | Cardano エクスプローラ + コンテンツゲートウェイ |
| 受信者検証者 | 封緘済みペイロードの試行復号、平文ハッシュ値の再計算 | 検証者自身の秘密鍵 |
構造バリデーター — バイト列に対する純粋関数
構造バリデーターは、バイト列を結果へ写す単一の関数です。I/O も、暗号署名の検証も、復号も一切行いません。 ネットワーク、トランザクション、鍵を目にすることはありません。同じ入力を与えれば、いつでも、どこでも、 同じ出力を返します。だからこそ、サーバーを一切介さずに、発行者のツール内での提出前チェック、サードパーティ のインデクサー内、あるいは長期的な整形性を確認するアーカイブツール内で動かせるのです。
そのパイプラインは固定されています。
1. resource bounds — a local, non-normative guard on input size; never a
Label 309 conformance error.
2. canonical decode — decode with a canonical-CBOR decoder (RFC 8949 §4.2.1):
definite lengths, sorted map keys, no duplicate keys,
valid UTF-8. Any malformed or non-canonical input →
a single MALFORMED_CBOR.
3. schema parse — type, length, and the chunk/length bounds; a strict
object mode that rejects unknown fields.
4. domain rules — cross-field constraints the schema cannot express:
registry membership, the items-or-merkle rule, COSE
structural shape, URI reconstruction, envelope shape.
5. result — { valid, record } with optional warnings/info, or a
sorted list of typed issues.バリデーターはプロファイル非依存です。下流の検証者がどの部分集合に対して動作させようとしているかに
かかわらず、v1 スキーマ全体をパースします。エラーはレコードを不合格にします。警告と情報エントリは
表面化されますが、レコードは有効なままです。重要な点として、バリデーターは COSE*Sign1 の *形状_、
すなわち4要素の配列、デタッチされた(null の)ペイロード、整形された保護ヘッダーを確認しますが、
署名そのものは決して検証しません。また、署名アルゴリズムが認識できないものであるという理由だけで
レコードを拒否することもありません(その場合は SIGNATURE_UNSUPPORTED、severity は info でタグ付け
され、レコードは有効なままです)。署名の検証は公開検証者の仕事です。このパスが強制するスキーマについては
レコード を参照してください。
公開検証者 — チェーン、包含、署名
公開検証者は、構造バリデーターの上にチェーンを重ねます。Cardano のトランザクション参照を与えられると、 次を行います。
- 検証者が選んだエクスプローラを解決する。 エクスプローラの連鎖は入力です。検証者はそれらを順に
試し、生のオンチェーンのトランザクション CBOR を取得します。エクスプローラのメタデータ JSON
投影ではありません。JSON ビューは CBOR の主要型を JSON のユニオンへ畳み込み、マップキーの順序、
確定長のフレーミング、バイト列とテキストの区別を捨ててしまうため、それから再エンコードした検証者は
バイト単位で厳密な署名入力を再現できず、準拠レコードのすべての署名が失敗してしまいます。単一の
プロバイダの否定的な答えはチェーン上で権威があるわけではありません。トランザクションはチェーン上に
あって、たまたまそのプロバイダが知らないだけかもしれないからです。そのため検証者は
TX_NOT_FOUNDを 発する前に残りのすべてのプロバイダに問い合わせます。すべてのプロバイダが到達不能ならPROVIDER_UNAVAILABLEを発します。 - 取得したバイト列をトランザクション参照に束縛する。 取得したトランザクションから何かを読み取る前に、
検証者は取得したトランザクション本体のバイト列に対して
blake2b-256を再計算し(レジャーの定義により、 これがトランザクション id です)、要求したハッシュと一致しない応答を拒否します。次に、取得した auxiliary-data のバイト列に対してblake2b-256を再計算し、検証済みとなった本体のauxiliary_data_hashと一致しないものを拒否します。どちらのダイジェストも、再エンコードではなく取得したとおりのバイト列に 対して計算されます。どちらかのチェックに失敗した応答は、明らかに誤ったバイト列を運んでいるため破棄されます。 束縛を生き延びる応答をどのプロバイダも返さなければ、レポートはTX_INTEGRITY_MISMATCHを運びます。 このステップの後、レコードと周囲のトランザクションのあらゆるバイトは、呼び出し側が与えたハッシュへ 暗号的にコミットされています。いかなるエクスプローラも、blake2b-256 の第二原像を作り出すことなしには、 レコードを差し替え、改変し、切り詰めることはできません。 - auxiliary data をアンラップする。 Conway 時代のレジャーは 3 つの auxiliary-data エンコーディングを
認め、いずれも有効です。タグの付かない素のメタデータマップ、2 要素の
[ metadata, scripts ]配列、そして メタデータをキー0に置いたタグ 259 のマップです。検証者はこの 3 つすべてを受け入れなければならず(MUST)、 トップレベルの CBOR の型とタグだけで振り分けなければなりません。タグ 259 の値はキー付きマップの形、 タグの付かない配列は 2 要素の形、タグの付かないマップは常にメタデータマップそのものです。マップのキーを 調べて形を推測してはなりません(MUST NOT)。それ以外のトップレベルの形、または 259 以外のタグはMALFORMED_CBORです。束縛されたトランザクションが label 309 のメタデータを持たない場合、検証者はMETADATA_NOT_FOUNDを発します。これはレコードに起因する結果です。束縛されたトランザクション自身が その不在を証明しているからです。束縛を破ることなくメタデータを取り除けたプロバイダは存在しません。 - 本体全体のチャンク配列を再構成する。 label 309 の値は、正準 CBOR のレコード本体を 64 バイト 以下のバイト列の配列に分割したものです。検証者は要素を順にバイト連結します。再エンコードのパスを挟まず 生のバイト列を返すため、オンチェーンのエンコードが非準拠であっても正準 CBOR のチェックがそれを捕捉 できます。
- 再構成した本体を 構造的に検証する(上位のロール)。バリデーターの拒否は、レポートを判定
failedで 短絡させます。 - 確認の深さをチェックする(後述)。しきい値を下回るトランザクションは、ここで判定
pendingとして 止まります。 - 厳格な Ed25519 のもとで すべてのレコードレベルの署名を検証する。復号は行いません。署名の解決、 ドメイン分離されたペイロード、厳格な検証規則は 署名 で規定されています。
- コンテンツを取得してハッシュ照合する。 レコードに責めを負わせるのは、URI 自身のコンテンツアドレスに 帰属できるバイト列に限ります(後述)。復号は行いません。
なぜ JSON ではなく生の CBOR なのか
署名はレコード本体のバイト単位で正準な CBOR に対して計算されます。メタデータの JSON 投影は構造上 劣化しており、そのバイト列へ往復で戻すことができません。JSON からの再エンコードは、準拠レコードの すべての署名を壊します。生のトランザクション CBOR は、あらゆる暗号チェックにとって唯一の権威ある入力 です。JSON ビューは、検証がすでに通過したあとの、人間向けの表示用です。
受信者検証者 — 復号して再計算する
受信者検証者は、さらに秘密鍵を持つ公開検証者です。自分宛に封緘された項目について、オンチェーンの鍵 スロットを自分の鍵で 試行復号 し、成功すればコンテンツ鍵を回収して暗号文を復号し、続いてオンチェーン のコミットメントに対して 平文のハッシュ値を再計算 します。これにより、暗号化されたバイト列とコンテンツ の存在主張との間の輪が閉じます。封緘済みの項目はすべて少なくとも1つのコンテンツハッシュのエントリを携えて いるため、この再計算には常に照合すべき具体的な対象があります。封緘エンベロープ、鍵スロット、アンラップの 構成は 封緘済み PoE で規定されています。
受信者がいかなる KEM や AEAD のプリミティブに触れる前に、構造検証者がすでに実行したのと同じエンベロープの
形とリソースのチェックを再度かけ、構造的に無効な、あるいは過大なエンベロープをまず拒否します。これらの
プリミティブ前ガードのうち 2 つは、ワイヤーフィールドではなくデプロイ固定のリソース上限です。参照上限は
MAX_SLOTS = 1024 スロットと、デコード後の enc エンベロープに対する 65536 バイトであり、いずれも、
正直なレコードに上限を課す約 16 KiB の Cardano トランザクションメタデータ天井をはるかに上回ります。
したがって、どちらかを超えるレコードは不正形式であり、ただ 1 つのプリミティブが走る前に ENC_SLOTS_TOO_MANY
または ENC_ENVELOPE_TOO_LARGE で拒否されます。デプロイ側でより厳しくしてもかまいません(MAY)。
形のチェックの 1 つはセキュリティ上の要となります。カプセル化材料は 1 つの slots[] の中で互いに異なって
いなければなりません(MUST)。x25519 ではすべての epk 値が、mlkem768x25519 ではすべての
kem_ct 値が異なっていなければなりません。レコード内の重複は、いかなる KEM や AEAD のプリミティブが走る前に
ENC_SLOTS_DUPLICATE_KEM_MATERIAL で拒否されます。epk / kem_ct の重複は、全ゼロノンスのラップが依拠する
スロットごとの鍵の一意性を壊すからです。レコードをまたぐ、あるいは鍵をまたぐ鍵の再利用はプロデューサーの義務
であり、検証者には検知できません。検証者が検知できるのは、レコード内の重複だけです。これら 3 つのチェックは
いずれも構造的なものであり、構造検証者がすべてのレコードに対して強制します(重複材料・スロット数・デコード後
エンベロープの各コードは Part-A のコードです)。受信者は、多層防御として単にそれらをもう一度走らせるだけです。
アンラップそのものは、受信者がエンベロープから、いかなる外部入力からでもなく再現する 2 つの暗号ステップ
です。まずスロットトランスクリプトのハッシュ slots_hash をループの前に 1 度だけ再計算し、すべての
スロットを通じて一定に保ちます。
slots_hash = SHA-256("cardano-poe-slots-transcript-v1" || canonicalEncode(SLOTS_TRANSCRIPT))
であり、トランスクリプトはヘッダーフィールド、ワイヤー上のスロット集合(各スロットフィールドは単一の
バイト文字列であり、正規化すべきフィールドごとのチャンク化はありません)、そして hashes_hash を介した
アイテムのハッシュ主張を固定します。hashes_hash を結合することこそが、受信者が、いかなる暗号文の取得よりも
前に、オンチェーンのバイト列だけからエンベロープがこの正確なハッシュ主張のために封緘されたことを確認
できるようにするものです。別の hashes マップを持つアイテムに継ぎ接ぎされたエンベロープは MAC が失敗します。
検証者は早期離脱なしにすべてのスロットを走査し、スロットは、それが生むコンテンツ鍵が、その一定の
slots_hash に対してワイヤー上の slots_mac も再現する場合に限って受理されます。受理にはさらに秘密に依存しない有効性ビットも織り込まれます。古典のパスでは、
X25519 共有秘密を全ゼロ値へ追い込むよう細工されたスロットは、そのビットを偽にし(0^32 との定数時間比較)、
KEK は 0^32 から導出したダミーへ定数時間で選択されるため、ループは同一の処理を行い、このビットがスロットの
受理を制御します。すなわち ECDH が無効なスロットは、その wrap や MAC によらず決して開きません。wrap の
開封も後段のコンテンツの開封もアトミックです。AEAD タグの失敗時には平文を返さず、返す候補(ラップ済みの
鍵、またはコンテンツの平文)は、失敗した暗号文とは独立した固定値または擬似乱数のダミーです。検証されていない
平文が外に出ることは決してありません。
受信者の鍵が複数のスロットに正当にマッチすることもありえます(MAY)。プロデューサーは、同じコンテンツ鍵を
同じ受信者へ、それぞれ新しいスロットごとの KEM 材料を伴って複数のスロットに封緘し、受信者数をパディングする
ことがあります。これは正当なプライバシー技法であり、同一の epk / kem_ct のときにのみ発火する重複カプセル化
材料の拒否とは別物です。検証者は最初のマッチの鍵を選び、複数のスロットがマッチしたというだけで拒否しては
なりません(MUST NOT)。必ず(MUST)拒否すべき唯一の異常は、異なるコンテンツ鍵を回収する 2 つの
マッチするスロットです(定数時間で比較します)。ループは cek_conflict ビットを保持し、後続のいずれかのマッチが、
選択済みの鍵と異なる鍵を生んだ場合には、単一の汎用的な失敗を表面化させます。これは多層防御です。スロット集合の
コミットメントのもとでは、異なる鍵を生むマッチはすでに実現不可能なので、このチェックは単にフェイルクローズします。
次に、回収したコンテンツ暗号化鍵で、コンテンツ鍵(その鍵の HKDF リーフで、enc.nonce をソルトとするもの)を
導出し、セグメント化された STREAM の暗号文をチャンクごとに開き、各チャンクの平文を放出する前にそのチャンクの
タグを検証します。チャンクごとの AAD は空です。すべてのヘッダーのコンテキストは、slots_mac を通じて推移的に
すでに鍵へ結合されているため、ヘッダーフィールドをどれか変えれば受信者が導出するものが変わり、ストリームは
開かなくなります。切り詰めはファイナルフラグによって捕捉されます。ファイナルチャンクの欠落、その後のデータ、
非ファイナルチャンクに付いたファイナルフラグ、あるいは短い非ファイナルチャンクは、いずれも TAMPERED_CIPHERTEXT
として失敗します。セグメント化されたフォーマットは暗号的なペイロード上限を課しません(88 ビットのチャンク
カウンターは 2^88 個のチャンクを許容します)。実用上の最大値は、ストリームの読み取り時に逐次的に課される
デプロイメントのサービス拒否(DoS)ポリシーです。passphrase 経路では、受信者はまず先頭の 32 バイトのコミットメント
ヘッダーを読み、いかなるチャンクを開くよりも前に定数時間で比較します。
受信者のパスこそ、エラーカタログがその精度を発揮する場所です。ここでは、どのスロットもこの鍵を受け付け なかった ケース(受信者違い)と、あるスロットは鍵を受け付けたものの スロット集合 または 暗号文 が 改ざんされていたケースとを区別します。これらは異なるセキュリティ上の主張であり、異なるコードを持ちます (後述)。ただし信頼できない呼び出し側は、原因にかかわらず、すなわちどのスロットも開かなかった、 スロット集合が改ざんされていた、コンテンツタグが失敗した、のいずれであっても、ちょうど 1 つの汎用的な 失敗の形を受け取ります。そして応答は、どのケースが起きたかも、どのスロットがマッチしたかも、決して 明かしません。型付きコードは、信頼できるローカルな呼び出し側のための内部診断にすぎません。
タイミングは 1 つの明示的なモデルに従います。検証者は、ノーマッチのチェックの時点で、すなわちコンテンツの 復号の前に、戻ってもかまいません(MAY)。そのため、受信者でない者と受信者とでは、計測可能なほど時間が 異なります。その差が明かすのは受信者か否かだけであり、どのスロットがマッチしたかも、鍵材料も決して 明かしません。受信者でない者と、暗号文の開封に失敗する受信者との間で、タイミングを一様にすることは要求 されません(NOT)。ダミーのコンテンツ開封を義務づけてはなりません(MUST NOT)。それは、通りすがりの すべての者にコンテンツ復号のコストを課すことになるからです。確かに成り立つ定数時間の保証はスロット横断の ものです。すなわち、単一の秘密鍵のパスの中で、ループは定数時間比較ですべてのスロットを走るため、その鍵が アンラップするのが どの スロットか(あるいはどれもアンラップしないか)は何も漏れません。
確定性: 確認の深さ
Cardano の決済は確率的です。1ブロックの深さしかないトランザクションは、短いリオーグで依然としてオーファン
になりえます。多くのブロックの深さに達したトランザクションは、圧倒的な確からしさで決済済みです。1ブロック
深のレコードを valid と呼ぶ検証者は、攻撃者が競合するフォーク上に矛盾するレコードを再記録し、その両方で
「valid」の判定を得ることを許してしまいます。これは、証明全体が依拠する追記専用の前提を密かに破壊します。
そこで検証者は、確認深さのしきい値を下回っている間、そのレコードを failed ではなく pending として
報告します。汎用途で 推奨される(RECOMMENDED) しきい値は 15 ブロック以上(おおよそ5分)です。この
しきい値はワイヤ定数ではなく検証者のポリシーです。高価値の記録や証拠性のある記録を扱うデプロイメントは、
ハードな確定性に向けてこれを引き上げる べきであり(SHOULD)、検証者は利用したしきい値を表面化し
なければならない(MUST)。これにより、利用側はより厳格なポリシーをその上に重ねられます。pending の
レコードは整形済みでオンチェーンにあります。まだ十分に深く決済されていないだけで、のちの再試行で valid に
解決される可能性があります。
確認深さ、ブロック高、ブロック時刻は、検証者が決して捏造しない、エクスプローラが主張する事実です。
トランザクション参照への束縛はトランザクションの内容を信頼不要にしますが、それに関するチェーンの事実は
バイト列から導けません。トランザクション CBOR はタイムスタンプも高さも運ばないからです。深さは
(解決したエクスプローラのチップ高) − (含むブロックの高さ) + 1 として計算されるため、チップブロックにある
トランザクションの深さはちょうど 1 です。ブロック時刻は、含むブロックのスロットの POSIX タイムスタンプ
(整数秒、UTC)であり、エクスプローラの時刻フィールドから取得され、検証者が再計算することは決してありません。
これらの事実はエクスプローラの言い分に依拠するため、検証者は少なくとも 2 つの独立したエクスプローラから
それらを解決し、相違があれば表面化すべきです(SHOULD)。ブロック時刻が要となるデプロイメント(法的な
公証、期限の争い)は、それをクロスチェックしなければなりません(MUST)。レポートは、比較に用いたしきい値
とともに解決した深さを運び、block_time(利用可能なら block_slot も)を運びます。
判定結果の状態
検証者は、4つの機械判定のいずれか1つで結論し、それぞれが1つの終了コードと一対一で対応します。これにより、
呼び出し側、すなわち CI ゲート、モニター、スクリプトは、構造化レポートをパースせずとも、レコードに起因する
失敗と一時的な運用上の失敗とを見分けられます。判定を貫く原則は帰属です。レコードを断罪するには、レコード
自身のバイト列、あるいはその参照に帰属可能に束縛されたバイト列が、実際に提供する証拠が必要です。いかなる
プロバイダの不正も failed を作り出すことはできません。
| 判定 | 終了コード | 意味 |
|---|---|---|
| valid | 0 | 検証者が実行したすべてのチェックが ok を返した。error 重大度の問題は1つもない。 |
| failed | 1 | レコードに起因する失敗。構造バリデーターがバイト列を拒否した、署名が検証されなかった、帰属可能なハッシュ値が一致しなかった、束縛されたトランザクションが label-309 メタデータを持たない(METADATA_NOT_FOUND)、または deny-host 規則が発動した。 |
| unverifiable | 2 | レコードに起因するエラーはないが、必須のチェックを実行できなかった、あるいは帰属できなかった。トランザクションが解決しなかった、束縛を生き延びるプロバイダ応答がなかった(TX_INTEGRITY_MISMATCH)、あるいはコミットされたコンテンツ/暗号文を取得または帰属できなかった。同じレコードが、再試行で、または別のゲートウェイのもとで valid と検証されることもある。 |
| pending | 3 | 構造的には整形済みでオンチェーンにあるが、確認深さのしきい値を下回っている(INSUFFICIENT_CONFIRMATIONS)。決済される可能性がある。pending のレコードから得られる結果を確定として提示してはならない。 |
レコードに起因しない検証者ホストのランタイム失敗は、終了コード 4 以上を用い、いかなる判定にも対応しません。
error 重大度の問題が1つでも存在する場合、valid の判定を報告しては ならない(MUST NOT)。空でない
warnings や info のリストを伴っていても、レコードは valid で ありうる(MAY)。レコードを通過させる
ために、いずれの層もエラーを警告に「軟化」させてはなりません。各判定はそれぞれのケース専用に予約されています。
pending が valid や failed の代わりに用いられることは決してなく、プロバイダに起因する失敗は failed では
なく unverifiable です。
コミットメントフロアが可用性を統べます。コンテンツチェックは実行されたものの、可用性の失敗によって、
実際に検証されたレコードのコンテンツコミットメントが1つも残らなかった場合、判定は valid ではなく
unverifiable です。valid の判定は、少なくとも 1 つのコンテンツコミットメントが検証されたことを意味します。
整合性の結果はこのフロアに左右されません。帰属可能なバイト列がコミットメントに失敗すれば、ほかに何が利用
可能であったかによらず failed を生みます。
コンテンツアドレス束縛と帰属
ステップ 8(そして受信者検証者では復号)は、検証者が選んだコンテンツアドレス指定のストレージゲートウェイから バイト列を取得します。そしてゲートウェイは信頼されません。上記の判定の線引きは、検証者が、取得したすべての バイトストリームについて答えられなければならない 1 つの問いにかかっています。これらのバイト列を URI 自身に 帰属できるか? 両スキームはコンテンツアドレス指定なので、帰属できます。
ipfs://— 取得したコンテンツに対して CID を再計算します(raw コーデックの CID なら multihash を直接、 DAG 形式の CID なら解決経路に沿ったブロックごとのダイジェスト)。ar://— 署名済みの Arweave トランザクションを検証し、そのdata_rootに対してチャンクの Merkle 木を 再計算します。ANS-104 のデータアイテムなら、deep-hash を再計算し、オーナー署名を検証し、署名の SHA-256 が URI 内の id に等しいことを確認します。
レコード自身のダイジェストを満たすバイト列は、束縛のチェックを必要としません。レコードのコミットメントは、 ストレージ層のそれと少なくとも同じだけ強いからです。束縛が適用される場合、不一致が何を意味するかは帰属が 決めます。
- 帰属可能なバイト列 — 束縛が検証された、あるいは呼び出し側がアウト・オブ・バンドで供給したもの — は、
コミットメントに失敗するとレコードの責めとされます。アイテムコンテンツには
URI_INTEGRITY_MISMATCH(いかなる 兄弟 URI が何を保持していようとハードな整合性の失敗)、リーフリストにはMERKLE_*ファミリー、帰属可能な 暗号文ブロブにはTAMPERED_CIPHERTEXTです。判定はfailed。 - 帰属できないバイト列 — 束縛が検証されていない、あるいは検証して失敗したもの — は、レコードではなく
配信したプロバイダを指弾します。
URI_PROVIDER_INTEGRITY_MISMATCH(警告)です。検証者は残りの URI と ゲートウェイで続行します。帰属可能なバイト列が一つも残らなかった主張は、可用性の結果(CONTENT_UNAVAILABLE、MERKLE_LEAVES_UNAVAILABLE、CIPHERTEXT_UNAVAILABLE)で終わり、判定はunverifiableです。何も取得しなかった 場合とまったく同じです。
これはトランザクション参照への束縛の、ストレージ側の対応物です。ふるまいの悪いゲートウェイは可用性だけを
劣化させられ、判定は決して劣化させられません。URI_INTEGRITY_MISMATCH と URI_PROVIDER_INTEGRITY_MISMATCH は
したがって別個のコードです。前者はレコードを断罪し、後者はプロバイダを断罪します。両者を混同する検証者は、
敵対的なゲートウェイに failed を偽造させてしまいます。復号後の平文ハッシュ再確認は帰属の限定を必要としません。
認証されたエンベロープのもとで開く暗号文は AEAD 自身によって帰属されるため、そこでの平文ハッシュの不一致
(URI_INTEGRITY_MISMATCH)は常にレコードに起因し、failed を強制します。
型付きエラーカタログ
あらゆる失敗モードは、単一の閉じたカタログのコードに解決されます。コードは SCREAMING_SNAKE_CASE であり、
準拠する実装はまさにそれらの文字列を出さ なければなりません(MUST)。パーサー内部の小文字コードでも、
自由形式のメッセージでもありません。2つの言語による2つの実装が同じ入力に到達したとき、同じコードを出します。
完全な規範リストは適合性テストスイートによってバイト単位で固定され、カタログはロックされています(コードの
追加は改訂によってのみ行われます)。
重大度モデル
あらゆる問題は3つの重大度のいずれか1つを携えており、この区別は本質的な役割を担います。
- error — 判定を無効にします。
validの結果は、いかなるerrorとも共存できません。 - warning — 致命的ではない実行時の異常(単一のゲートウェイが失敗した、葉のリストが一部しか得られ
なかった、など)であり、
validを妨げません。 - info — 意図的な非チェック。検証者が評価しないことを 選んだ 側面です(プロファイル外のフィールド、 認識されない任意のアルゴリズムなど)。info エントリは軟化されたエラーではなく、そのように用いられること も決してありません。
1つのコードだけは別格です。INSUFFICIENT_CONFIRMATIONS は重大度ではなく pending の判定に対応します。
レコードは整形済みであり、決済を待っているだけだからです。
エラーファミリー
カタログはファミリーごとにまとまっています。網羅的ではない代表的なコードの集合を示します。
| ファミリー | 重大度 | 代表的なコード |
|---|---|---|
| 不正/非正準な CBOR | error | MALFORMED_CBOR、CHUNK_TOO_LARGE |
| スキーマ | error | SCHEMA_TYPE_MISMATCH、SCHEMA_MISSING_REQUIRED、SCHEMA_UNKNOWN_FIELD、SCHEMA_EMPTY_RECORD |
| 未対応のアルゴリズム | error | UNSUPPORTED_HASH_ALG、UNSUPPORTED_AEAD_ALG、UNSUPPORTED_KEM_ALG、UNSUPPORTED_MERKLE_COMMIT_ALG |
| エクスプローラ / メタデータ | error / pending | TX_NOT_FOUND、PROVIDER_UNAVAILABLE、TX_INTEGRITY_MISMATCH(→ unverifiable)、METADATA_NOT_FOUND(→ failed);INSUFFICIENT_CONFIRMATIONS(→ pending) |
| 署名 | error / info | MALFORMED_SIG_COSE_SIGN1、SIGNER_KEY_UNRESOLVED、SIGNATURE_INVALID、WALLET_ADDRESS_MISMATCH;SIGNATURE_UNSUPPORTED(info) |
| 暗号化 / KEM / ラップ | error | KEM_EPK_LENGTH_MISMATCH、KEM_CT_LENGTH_MISMATCH、WRAP_LENGTH_MISMATCH、ENC_SLOTS_DUPLICATE_KEM_MATERIAL、ENC_SLOTS_TOO_MANY、ENC_ENVELOPE_TOO_LARGE、ENC_REQUIRES_CONTENT_HASH |
| 復号の結果 | error | WRONG_DECRYPTION_INPUT_SHAPE、WRONG_RECIPIENT_KEY、TAMPERED_HEADER、TAMPERED_CIPHERTEXT、KDF_DERIVATION_FAILED |
| URI / コンテンツ | error / warning | INVALID_URI、URI_TARGET_FORBIDDEN、URI_INTEGRITY_MISMATCH、CONTENT_UNAVAILABLE(→ unverifiable)、CIPHERTEXT_UNAVAILABLE(→ unverifiable);URI_PROVIDER_INTEGRITY_MISMATCH、URI_FETCH_FAILED(warning) |
| Merkle リストコミットメント | error / warning / info | MERKLE_ROOT_MISMATCH、SCHEMA_MERKLE_LEAF_COUNT_MISMATCH;MERKLE_LEAVES_UNAVAILABLE(dual);MERKLE_UNSUPPORTED(dual) |
| サービス非依存 | error | SERVICE_INDEPENDENCE_VIOLATION |
ネットワーク/ポリシーのコード(TX_NOT_FOUND、PROVIDER_UNAVAILABLE、CONTENT_UNAVAILABLE、
CIPHERTEXT_UNAVAILABLE)と、その不一致がレコードではなくプロバイダに対して証明される TX_INTEGRITY_MISMATCH
は、問題リストでは error 重大度(valid の判定を妨げます)ですが、レコードに起因しないため、failed では
なく unverifiable に対応します。URI_PROVIDER_INTEGRITY_MISMATCH は、同じ原則のもとでの取得ごとの警告です。
いくつかのコードは二重重大度を持ちます。ENC_UNSUPPORTED、MERKLE_UNSUPPORTED、OUT_OF_PROFILE_SKIPPED、
MERKLE_LEAVES_UNAVAILABLE で、既定では info/warning として読まれ、厳格なコンテキスト(受信者ロール、
merkle のみのエスカレーション、厳格なエンドツーエンドモード、あるいはコミットメントフロア)では error へ
昇格します。
受信者のパスは、診断面で最も精密なファミリーです。信頼できるローカルな呼び出し側に対しては、復号の失敗が
3 つの内部コードのいずれかに解決されます。WRONG_RECIPIENT_KEY は、どのスロットも与えられた鍵を受け付け
なかった(コンテンツ鍵が一度も回収されなかった)ことを意味します。TAMPERED_HEADER は、鍵は回収されたが、
候補のコンテンツ鍵が slots_hash に対して slots_mac を再現しなかった(スロット、ヘッダーフィールド、
あるいは slots_mac 自体が改変された)ことを意味します。TAMPERED_CIPHERTEXT は、スロット集合は無傷だったが、
鍵が回収された後にコンテンツ AEAD タグが失敗したことを意味します。この 3 つは、そのローカルな呼び出し側に
対しては構造的に区別可能であり、その境界が鍵素材を漏らすことはありません。信頼できない外部の呼び出し側に
対しては、この 3 つすべてが上述の単一の汎用的な失敗に畳み込まれ、応答の形では区別できません。タイミングモデル
のもとでは、許容される早期のノーマッチの戻りが WRONG_RECIPIENT_KEY(受信者でない者)を 2 つの受信者側の
改ざんの結果から分離しますが、その 2 つは互いにそれ以上の区別を持ちません。こうして、診断面の精密さがスロット
選択的あるいは鍵選択的なオラクルになることは決してありません。
コードが4つの判定にどう対応するか
構造バリデーターが出すコードは、レコードのバイト列が適合していないことを意味します。公開検証者は、それ以上の
チェーン処理や暗号処理を一切行わず、判定 failed(終了コード 1)とバリデーターの問題リストでレポートを短絡
します。構造検証が通過したあとにのみ出るコード、たとえば検証されなかった署名、帰属可能な一致しなかった
ハッシュ値、束縛されたトランザクションに対する METADATA_NOT_FOUND も同様に failed です。これらはいずれも
レコードに起因し、レコード自身のバイト列が提供する証拠だからです。
一時的な、あるいはプロバイダに起因する失敗は別の判定です。取得または帰属できなかったコンテンツ、到達不能な
エクスプローラ、あるいはトランザクション参照への束縛に失敗するバイト列を配信したプロバイダは、いずれも
unverifiable(終了コード 2)に対応します。どれもレコードの責めではなく、同じレコードが再試行で valid と
検証されることもあるからです。したがって終了コードが保つ区別は、失敗状態のあいだの三分法です。レコードに
起因する failed(1)、運用上またはプロバイダに起因する unverifiable(2)、そしてしきい値を下回る
pending(3)です。
いくつかのコードは文脈依存の重大度を持ちます。宣言したプロファイルより豊かなレコードを読む検証者(たとえば
ハッシュのみの検証者が封緘済みの項目に遭遇した場合)は、表示の文脈では余分なフィールドを info として報告し、
ハッシュの主張はなお検証します。あるいは厳格なエンドツーエンドの監査の文脈では、それを error として報告
します。同様に、認識されない 任意の 署名アルゴリズムは info です。コンテンツの存在主張はそれに依存しない
ため、勧告的な署名が検証不能であっても、公開のハッシュのみの証明は valid のままです。
サービス非依存は任意ではない
検証が発行者へ戻って問い合わせることは決してありません。準拠する検証者が行うあらゆる外向きの呼び出しは、
運用者が選んだインフラに向けられます。トランザクションのための Cardano エクスプローラと、ar:// や
ipfs:// のバイト列のためのコンテンツアドレス指定ストレージのゲートウェイです。これはコードコメント上の
約束ではなく、構造的に強制されています。
- あらゆるネットワーク呼び出しは単一のイーグレスラッパーを経由し、成功、失敗、再試行のいずれであっても
すべての 呼び出しについて
url、method、status、バイト数、目的を、レポート上の必須の監査証跡に 記録します。その証跡を生成できない検証者は、自らの非依存性を証明できません。 - そのラッパーは、デプロイ時に与えられる deny-host リストを受け取り、一致するホストへのあらゆる呼び出しを
SERVICE_INDEPENDENCE_VIOLATIONで即座に失敗させます。このリストは運用者の入力であり、適合性スイートは 実装者自身のドメインでそれを埋めます。Label 309 のワイヤ定数ではありません。 - 適合性ハーネスは、運用者自身のドメインがどこにも解決しないネットワークで、凍結された固定トランザクション
に対して検証者を実行し、検証者がなお
validを返すことを表明します。この表明はソースを grep することでは なく OS のネットワーク層で行われます。ハードコードされた IP で禁止ホストへ到達する検証者は、ソーススキャン は通過しても、このテストには失敗します。
検証者には到達可能な Cardano エクスプローラが必要であり、実装者固有のものは一切要りません。コンテンツ ゲートウェイ、受信者の秘密鍵、オフチェーンの葉のリストは任意の入力であり、それぞれコンテンツ、受信者、Merkle のチェックを開放します。そのいずれも標準が指名するサービスではなく、そのいずれも発行者ではありません。