正規化の候補 dcp-jcs-v2¶
英語版の参考訳です(02/11/2026 更新)。実験的で規範的ではない提案です。内容が異なる場合は英語版が優先されます。識別子とコードブロックは翻訳せずにそのまま掲載しています。
実験的でオプトインの候補 API は、公開済みバージョンに載っている SDK のバージョンに含まれています。
| 日付 | 2026 年 10 月 29 日 |
| バージョン | 1.2 |
| 分類 | 公開 |
| 状態 | 規範的ではなく、実験的で、無効です。 dcp-jcs-v1 が引き続き唯一の規範的な正規化のプロファイルであり、既定です。SDK の候補の API(§15 から §18)は実験的でオプトインです |
| コーパス | corpus.json(リビジョン design-2、187 ケース)と baseline-corpus.json(87 ケースに、選択 10 ケースとポリシー 3 ケースを加えたもの) |
| ラボのツール | tools/canonicalization-lab/:設計モデル、コーパスの生成器、ランナー |
注意。 この文書は候補のプロファイルを提案し、その設計を記録します。
dcp-jcs-v1もspec/CANONICALIZATION_PROFILE.mdも変えず、 それらが引き続き唯一の規範的な参照です。既存のどの検証器、署名者、スキーマ、適合性の確認、既定値も 識別子dcp-jcs-v2を使いません。§15 から §18 の実験的でオプトインの API はそれを認識しますが、 有効にはしません。既存の経路や既定の経路はそれらを呼ばず、呼ぶのはオプトインした呼び出し元だけです。§15 と §16 の API は何も検証しません。§17 の検証器は候補のバンドルを元のバイト列から検証し、 検証済みのバンドルは信頼もアドミッションも与えません。§18 の生成側は、そうした呼び出し元のためだけに 新しい候補の証拠を作ります。フェーズ 3 のベクターはテスト専用の生成器が署名しています。実験的なオプトイン API は npm の SDK 2.2.0 と WASM 2.1.0 で利用できます。他の環境の公開は別です。公開済み npm パッケージを参照してください。ラボのツールの CI のジョブは 設計モデルを実行し、SDK のテストのジョブはそれらの API をコーパス、フェーズ 3 のベクター、ゲート 7 のフィクスチャに対して実行し、 フェーズ 4 のマトリクスには独自のワークフローがあります。 既存の V2 の検証器、たとえば TypeScript の SDK のもの (verify-v2.ts)は、解析済みのオブジェクトやテキストを受け取ると、 引き続きこのプロファイルを未知のものとして拒否し、それが意図した動作です。ここにあるものはどれも適合性の要件ではありません。ラボの ツールは設計の実行可能なモデルであって実装ではありません。合成のコミットメントのために SHA-256 を 計算しますが、何にも署名せず、どの署名も検証しません。
1. なぜ候補なのか¶
dcp-jcs-v1 は、JSON のパーサーが返す値を正規化します。JSON のパーサーは同じテキストに対して常に同じ
値を返すわけではありません。RFC 8259 は、重複したメンバー名(§4)、エスケープ中の孤立したサロゲート(§8.2)、
先頭のバイトオーダーマーク(§8.1)を実装に委ねており、数値を binary64 として読むパーサーは、
異なるリテラルを同じ値に変えることがあります。そのため、1 つのテキストを読む 2 つの読み手が、異なる正規の
バイト列、ハッシュ、署名の入力を計算することがあり、署名者が見ていない値(たとえば前にある重複した
メンバー)が署名された証拠とともに運ばれることがあります。
候補は dcp-jcs-v1 の出力の規則を保ち、どのパーサーも情報を修復、丸め、欠落させる前に、
元のバイト列で受け入れを決めます。
2. 原則¶
- 同じ値には
dcp-jcs-v1と同じバイト列。 候補は出力の規則を変えず、どの入力を受け入れるかを 狭めるだけです。その定義域の正確な値については、どちらの正規化器も同じ バイト列を生成します。 - 受け入れは元のバイト列で決める。
- プロファイルは、マニフェストの署名されたフィールドから一度だけ選ぶ。 未知のプロファイルは拒否され、 失敗の後にほかのプロファイルが再試行されることはありません。
- JCS ではない。 キーは
dcp-jcs-v1と同じく Unicode のコードポイント順に並べます。RFC 8785 §3.2.3 は UTF-16 のコード単位で並べます。このプロファイルは JCS との互換性を主張しません。 - 黙ったダウングレードはない。 候補を知らない検証器はそれを拒否します。
3. 規則¶
3.1 入力(バイト列)¶
| 規則 | 要件 | クラス |
|---|---|---|
| I1 | 正しい形式の UTF-8:不正なバイトなし、冗長な形式なし、符号化されたサロゲート(ED A0 80)なし、U+10FFFF を超えるものなし |
UTF8_INVALID |
| I2 | 先頭に U+FEFF(EF BB BF)がない |
BOM |
| I3 | ちょうど 1 つの RFC 8259 の JSON テキスト:空白はスペース、タブ、LF、CR だけ、値の後には何もなく、NaN、Infinity、+1、01、1.、末尾のカンマもない |
SYNTAX |
| I4 | 入れ子の配列とオブジェクトは、検証する単位のルートから数えて最大 64(§5) | DEPTH_EXCEEDED |
3.2 文字列とキー¶
- S1. スカラー値。 キーを含むすべての文字列は、Unicode のスカラー値の並びです。
\uD800–\uDBFFのエスケープの直後には\uDC00–\uDFFFのエスケープが続かなければならず、その組は 1 つのスカラー値を表します。それ以外のサロゲートのエスケープはSURROGATE_UNPAIREDです。 - S2. 修復しない。 U+FFFD は、エスケープでもリテラルでも正当な文字です。拒否するのは、パーサーが U+FFFD に変えてしまうデータです。
- S3. 非文字は受け入れる(D2)。
- S4. 正規化しない。
dcp-jcs-v1の規則 9 と同じく、"é"(U+00E9)と"e\u0301"は異なる文字列であり 異なるキーです。 - S5. キーは一意。 1 つのオブジェクトの 2 つのメンバーは、エスケープを解いた後に同じキーを持つことはできません
(
DUPLICATE_KEY)。値が等しくても、どの深さでも、特別扱いはありません(__proto__もほかと同じ キーです)。
3.3 数値¶
- N1. リテラルの正確な値。 受け入れは、リテラルの binary64 への変換ではなく、
リテラルの正確な 10 進の値で決めます。整数でない値は
NUMBER_NOT_INTEGER、[-(2^53-1), 2^53-1]の外の整数はNUMBER_OUT_OF_RANGEです。 - N2. 受け入れる形式。 正確な 10 進の値が範囲内の整数であるリテラルは、その形式に
かかわらず受け入れます。
1.0は1、1e2と1E+2は100、100e-2は1、1.5e1は15、そして-0、-0.0、0e-400は0です。これはdcp-jcs-v1が受け入れるすべてのリテラルではありません。binary64 のパーサーが 整数に丸める1.0000000000000001のようなものは拒否されます(N3)。 - N3. 範囲内の正確な整数ではないため拒否されるもの:
0.5、2^53、1e-400、0.99999999999999999、1.0000000000000001、4503599627370497.5、9007199254740993、1e21。 - N4. 大きな数の演算を使わないアルゴリズム。 リテラル
-?E(.F)?(e[+-]?X)?について: D= 先頭のゼロを除いたEとFの数字、s = X − len(F)。空のDは0。Dの末尾のゼロを取り除き、その個数をsに足す。s < 0なら、値は整数ではない。len(D) + s > 16なら、値は 10^16 以上で範囲外。- それ以外は
D·10^sを2^53-1と比べる。
X は len(literal) + 17 で飽和させて読みます。その上限を超えると結果は変わりえません。小数でもあり
範囲外でもあるリテラルは NUMBER_NOT_INTEGER です(手順 3 が手順 4 より先)。
- N5. アプリケーションの大きな整数は、スキーマでそう宣言した 10 進の文字列に入れます。
- N6. 値はリテラルから来る。 候補のもとで正規化される数は、N4 が計算するものであり、
binary64 のパーサーが返すものでは決してありません。dcp-jcs-v1 の経路は変わりません。
3.4 出力¶
dcp-jcs-v1 の出力の規則(規則 1–3 と 5–8):すべての深さでコードポイント順に並べたキー、
コンパクトな形式、RFC 8785 §3.2 のエスケープ(\b \t \n \f \r、C0 の残りには小文字の \u00xx、\" と
\\)とそれ以外のすべてをリテラルの UTF-8 で(/、U+007F、U+2028、U+2029 を含む)、小数部も
指数もない整数、0 としての -0、リテラルの null、true、false、保持される {} と []。
4. 設計上の判断¶
| # | 判断 | 理由 | 互換性 |
|---|---|---|---|
| D1 | 単位の先頭の BOM を拒否する(BOM、オフセット 0)。伝送のエンベロープの前の BOM は伝送の欠陥 |
RFC 8259 §8.1 は受信側がそれを無視することを認めており、読み手によって異なる(取り除くものも拒否するものもある)。拒否すれば違いがなくなる。文字列の中の U+FEFF は内容 | dcp-jcs-v1 の経路は変わらない(§7) |
| D2 | 非文字を受け入れる(U+FFFE、U+FFFF、その他) | それらは UTF-8 の符号化と正規の形がそれぞれ 1 つしかないスカラー値。拒否すれば正規化の規則ではなく内容のポリシーになる | このプロファイルは I-JSON ではなく(RFC 7493 §2.1 はそれらを禁じる)、そうだと主張もしない |
| D3 | 入れ子は最大 64 段で、検証する単位のルートから数え(署名付きバンドルのバイト列)、伝送のエンベロープを含めて数えることはない(§5) | 有効性が、伝送がエンベロープを加えるかどうかに左右されてはならない。64 は serde_json の既定の再帰の上限(128)を下回る。ほかのパーサー、数値やほかの上限、より低いこともある運用者の予算についての保証ではない |
候補を選ぶ単位にだけ影響する |
| D4 | リテラルの正確な値(N1–N6) | 基準は [-(2^53-1), 2^53-1] の正確な整数。それ以外はすべて拒否する。binary64 が正確に表せるが定義域の外にあるリテラル(0.5、2^53)と、binary64 が別の値として読むリテラル(1e-400 を 0 として)。コストは線形で、リテラルの長さは伝送の予算であってプロファイルの規則ではない |
候補を選ぶ単位にだけ影響する |
| D5 | 有効化の範囲外: マニフェストのないアーティファクト(失効、鍵のローテーション、マンデート)と A2A | プロファイルはマニフェストの署名されたフィールドで宣言され、それらのアーティファクトにはそのフィールドがない。後の設計で各型に独自の署名されたフィールドを、A2A にはハンドシェイクの記録の中のフィールドを与えることができる | dcp-jcs-v1 のままである。検証器はポリシーによってそれらに厳格な入力を適用できるが、生成側が候補を約束したと主張することはできない |
| D6 | 候補の名前 dcp-jcs-v2 は予約されている。 それを出力するのは、呼び出し元が求めたときの §18 の実験的でオプトインの生成側だけで、公開済み npm パッケージを含め、既定の経路では出力しない。規範的な文書が承認されるまでは候補の名前のままである。(フェーズ 4 で改訂:§18 より前には、オプトインの SDK の生成側はなく、フェーズ 3 のベクターはテスト専用の生成器から来ていた。) |
通信路上の草案の接尾辞は、維持すべき識別子をもう 1 つ増やすだけ。検証器は明示的なポリシーを通じてだけそれを有効にする(§7) | 候補のもとで出された証拠は実験的。外部への公開の後に規則が変われば、新しい識別子が必要になる(dcp-jcs-v1 §5) |
| D7 | 省略可能な dcp-jcs-v1 の警告。 バイト列があれば、検証器は dcp-jcs-v1 の結果に、主な欠陥のクラスとオフセットを示す警告を加えてもよい(§6) |
移行の前に直すべき生成側を見つけられる | dcp-jcs-v1 の判定を変えることは決してない。オブジェクトに基づく API はこれを出せない |
5. 検証する単位と伝送¶
単位とは、署名付きバンドルの値({"bundle": …, "signature": …})の正確なバイト列です。そのルートは
深さ 1 で、ペイロードは深さ 4(ルート、bundle、アーティファクト、payload)から始まるため、ペイロード自身の入れ子は
61 段まで可能です。オフセットは単位の最初のバイトからの相対値です。
伝送はエンドポイントの設定で決まり、内容から推測されることはありません:
| 伝送 | 単位 |
|---|---|
bare |
入力全体:HTTP のボディ、ファイル、またはヘッダーの値(それ自身の復号の後) |
envelope |
最上位のオブジェクトのただ 1 つの signed_bundle のメンバーの値 |
再シリアライズしない抽出。 エンベロープは、文字列を復号せずに区切るバイトのレベルの文法でたどります。
メンバー名はエスケープを解いた後に比べるため、"signed\u005fbundle" も
単位を指します。単位は値の [start, end) の範囲で、そのまま渡されます。その重複、
数値のリテラル、エスケープは損なわれずにスキャナーに届きます。エンベロープのほかのメンバーは解釈されず、
伝送のサイズと深さの予算は別です。
限界。 エンベロープの中で、文法が壊れている単位は区切ることができず、
TRANSPORT_INVALID になります。同じ単位をエンベロープなしで送ると SYNTAX です。どちらも拒否されます。文字列の中の欠陥、
重複、数値、深さについては、エンベロープはクラスも単位からの相対オフセットも変えません。
新しい、オプトインの契約。 バイトのレベルの抽出は、現在のオブジェクトに基づく解析が受け入れるエンベロープ
(繰り返された signed_bundle のメンバー、エンベロープの前の BOM)を拒否します。これは新しいバイト列の API か
明示的なオプションに属し、独自の互換性の注記を伴い、dcp-jcs-v1 の経路の上に黙って
導入することはできません。
なぜエンベロープを数えないのか。 伝送の文書全体で深さを数えると、有効性が伝送に左右されます。
同じ 64 段のバンドルが、エンベロープなしでは有効で {"signed_bundle": …} の中では無効になり、
ボディを包み直すプロキシが判定を変えてしまいます。ラボのツールは比較のためにその規則を評価できます
(depth_scope: "transport"、ケース d-unit-64-envelope-v03-rule と
b-v2-unit-depth-64-envelope-v03-rule)。
6. 優先順位¶
6.1 スキャナーの診断、層ごと¶
単位のスキャナーの診断の中では、オフセットにかかわらず、前の層が常に勝ちます。層は どの違反が主なものかを選びます。それが拒否になるかどうかはパイプラインが決めます(§6.4)。
| 層 | クラス | オフセット | 層の中では |
|---|---|---|---|
| 1. 符号化 | BOM、UTF8_INVALID |
BOM:0。UTF8_INVALID:最初の不正な部分列の最初のバイト |
BOM はオフセット 0 にあり、勝つ |
| 2. 文法 | SYNTAX |
どの JSON テキストの接頭辞も延ばせない最初のバイト。早く終わった場合は入力の長さ | 1 つだけ:最初のもの |
| 3. 値 | SURROGATE_UNPAIRED、DUPLICATE_KEY、NUMBER_NOT_INTEGER、NUMBER_OUT_OF_RANGE、DEPTH_EXCEEDED |
§6.2 | 最も早いオフセット |
6.2 値の層のオフセット¶
| クラス | オフセット |
|---|---|
SURROGATE_UNPAIRED |
組になっていないエスケープのバックスラッシュ |
DUPLICATE_KEY |
キーの 2 回目の出現の開きの引用符 |
NUMBER_NOT_INTEGER, NUMBER_OUT_OF_RANGE |
リテラルの最初のバイト |
DEPTH_EXCEEDED |
65 段目を開く角かっこまたは波かっこ |
キーはバイト列の中で先に来るため、キーの欠陥はその値の欠陥より先になります。キーは
エスケープを解いた後に単位の並びとして比べます。正しい組は 1 つのスカラー値で、孤立したサロゲートは
1 つの単位のままです。1 回の走査で 2 つの違反がオフセットを共有することはありません。念のため、同じオフセットは
表の順に従います。64 段を超えた後も、スキャナーは単位の終わりまで文法の確認を続けます。
そこでの値の層の欠陥はもう勝てません。そのオフセットは 65 段目を開いた角かっこより後に来るからです。
スキャナーは反復的です。2 万段でも再帰の上限なしに DEPTH_EXCEEDED になります。
6.3 伝送のフェーズ¶
エンベロープでは、オフセットではなくフェーズが決めます:
| フェーズ | 確認すること | クラス / 詳細 | オフセット(入力の先頭から) |
|---|---|---|---|
| T1 | エンベロープの前の BOM | TRANSPORT_INVALID / BOM |
0 |
| T2 | 単位を含むエンベロープ全体のバイトのレベルの文法 | TRANSPORT_INVALID / SYNTAX |
層 2 と同じ |
| T3 | ルートがオブジェクトである | TRANSPORT_INVALID / NOT_AN_OBJECT |
ルートのもの |
| T4 | signed_bundle のメンバーがちょうど 1 つ |
TRANSPORT_INVALID / NO_SIGNED_BUNDLE、または TRANSPORT_AMBIGUOUS / SIGNED_BUNDLE_REPEATED |
なし、または 2 つ目のメンバーの名前 |
| T5 | 単位の外の正しい形式の UTF-8。まず単位の前、次に後 | TRANSPORT_INVALID / UTF8_INVALID |
不正な部分列の最初のバイト |
エンベロープの符号化は単位の外でしか判断できず、単位は T2–T4 の後にしか存在しません。単位は
5 つのフェーズの後に走査されます。たとえば {"bad":"<FF>","signed_bundle":{},"signed_bundle":{}} は、
不正な UTF-8 がオフセット 8 にあるにもかかわらず、オフセット 30 で TRANSPORT_AMBIGUOUS です。
6.4 パイプライン全体¶
- 設定(バンドルのみ):入力を読む前の
POLICY_INVALID。 - 伝送(エンベロープのみ):フェーズ T1–T5。
- 単位のスキャナー: 主な診断、またはなし。
- 文書: 診断があればそのクラスで拒否し、なければ正規のバイト列を生成する。
- スキャナーがたどれるバンドル(符号化や文法の診断がない):
unknownの読み取りは、値の層の診断があってもPROFILE_UNKNOWN;- ポリシーの外のプロファイルは、診断があっても
PROFILE_NOT_ACCEPTED; absentまたはdcp-jcs-v1はdcp-jcs-v1の経路に委譲され、診断は警告にすぎない(D7);- 診断のある
dcp-jcs-v2はそのクラスで拒否される; - 診断のない
dcp-jcs-v2は、合成のバンドルの確認を次の順で通る:その 構造、payload_hash、intent_hash、audit_chain、manifest_hash。最初の失敗は、その詳細を伴うCOMMITMENT_MISMATCH。そうでなければバンドルは受け入れられる。 - スキャナーがたどれないバンドル(符号化または文法の診断がある):
- 現在のパーサーが失敗するか、
dcp-jcs-v2やほかの値を読んだ場合は、診断のクラス; absentまたはdcp-jcs-v1を読んだ場合は、ポリシー(dcp-jcs-v1がなければPROFILE_NOT_ACCEPTED)、次に警告を伴う委譲。
7. プロファイルの選択とポリシー¶
読み取り。
- 正確な経路。 選択するのは、単位のルートからの
bundle.manifest.canonicalization_profileだけです。同じ フィールドがほかの場所にあればデータです。ルート、bundle、signature、ペイロード、または配列である マニフェストの中のものです。 - 重複。 経路上のキー(
bundle、manifest、そのフィールド)が繰り返されると、一般的な JSON のパーサーが 保持するのと同じく、最後の値を読みます。 - エスケープを解いた後の比較。
"dcp-jcs-v\u0032"と"canonicalization\u005fprofile"も数えます。 - 結果:
absent、dcp-jcs-v1、dcp-jcs-v2、またはunknown(ほかの文字列、大文字小文字や空白の 違い、""、null、数値、配列、オブジェクト、孤立したサロゲートを含む文字列)。
スキャナーがたどれない単位についてだけ、現在のパーサーに問い合わせ、それも
dcp-jcs-v1 の経路を進めるかどうかを決めるためだけです。パーサーの修復が候補を受け入れることは決してなく、拒否のクラスは
どこでも同じです。
委譲。 v1_path は単位をそのまま、現在の dcp-jcs-v1 の検証器に渡します。スキャナーがたどれる単位では、
スキャナーは最後の重複を保持するパーサーと同じようにフィールドを読みます。たどれない単位では、
現在のパーサーが決めます。dcp-jcs-v1 の判定が保たれることは、パーサーが経路をどう読むかに基づく
設計上の論拠です。ラボの設計モデルはそれを測りません。SDK のフェーズが測ったものは
§16 から §18 にあります(たとえば §16 のデコーダーの読み取りと §18.1 のマトリクス)。
ポリシー。 accepted_canonicalization_profiles は、繰り返しのない既知の識別子の空でないリストです。
それ以外のもの(空のリスト、裸の文字列、null、[[]]、[{}]、[1] のような文字列でない要素、
繰り返し、未知の識別子)は POLICY_INVALID で、データの拒否ではなく設定のエラーです。ポリシーは
制限するだけで、選択することは決してなく、その順序は関係ありません。ラボのツールには既定の
ポリシーがありません。各ケースが自分のものを示し、候補は明示的にだけ有効になります
(["dcp-jcs-v1", "dcp-jcs-v2"])。将来の本番の既定値は ["dcp-jcs-v1"] になるでしょう。
再試行はない。 1 つのプロファイル、1 つの経路です。候補の経路の失敗は最終的です。何も
dcp-jcs-v1 で正規化し直されず、プロファイルが内容、ヘッダー、パラメーターから推測されることもありません。
8. 署名されたプロファイル、内側の署名、監査チェーン、移行¶
- フィールドは署名されている。 それはマニフェストの一部で、マニフェストはバンドルの署名が覆います。
候補のもとでは重複がないため、約束はあいまいではありません。
dcp-jcs-v1のもとでは、繰り返された フィールドのうち最後のものだけが署名される正規のバイト列に入るため、署名されたものの前に置かれた繰り返しのフィールドは 署名を壊しません。候補はそれをなくし、D7 はそれを知らせることができます。 - 内側の署名はプロファイルを持たない。 定義域の中では、アーティファクトのバイト列は両方のプロファイルで
同じなので、候補への約束はマニフェストからしか来ません。内側の署名だけでは、
どのプロファイルがそれを作ったかはわかりません。バンドルの外のアーティファクトは
dcp-jcs-v1のままです(D5)。 - 監査チェーンは
GENESISから始まる。 現在の検証器は、最初のエントリーでprev_hash == "GENESIS"を 求めます(verify-v2.ts)。候補のバンドルの最初のprev_hashとしてコピーされたdcp-jcs-v1のハッシュは、プロファイルをまたいだ検証可能なつながりではなく、 チェーンを壊します(ケースmig-copied-v1-hash)。候補の証拠は独自のチェーンを始めます。ペイロードの中で 以前の証拠を参照すれば、それを特定はしますが検証はしません(mig-reference-is-data)。 プロファイルをまたいだ 1 つのチェーンの連続性には、ここでは設計していない仕組みが必要です。 - ラベルの付け替え。 候補としてラベルを付け替えた
dcp-jcs-v1はマニフェストのハッシュで失敗し、dcp-jcs-v1で再試行されることはありません(mig-relabel-v1-to-v2)。dcp-jcs-v1としてラベルを付け替えた、 またはフィールドを削除した候補はdcp-jcs-v1に委譲され、その検証器は生成側が署名していないマニフェストを ハッシュします。ラボのツールはその判定を計算しません。候補のバンドルの中の定義域の外のリテラルは、 binary64 の読み手には一致する値に見えるとしても、入力の段階で拒否されます。代替の経路はありません。 - 自動でラベルの付け替えや再署名はしない。 候補のもとの証拠は、新しい署名を持つ新しい証拠です。 保管すべきなのは受け取ったバイト列で、再シリアライズしたオブジェクトではありません。
9. フェーズと受け入れのゲート¶
ここでは何も有効にしていません。実装されているのは、実験的な単位の入力(§15)、ルーター(§16)、バイト列の検証器(§17)、生成側(§18)だけです。後のフェーズに進むには、この文書とは別に下される 明示的な決定が必要で、既定値の変更にはそれ自体の決定が必要です。
フェーズ。
- 提案、コーパス、設計モデル(この文書)。
- 明示的なオプションの背後で候補を検証できる検証器。生成側はまだ
dcp-jcs-v1。 - 下の署名の交差マトリクスが通った後の、明示的なオプションを持つ生成側。
- 後のサイクルでの、非推奨の注記を伴う既定値の変更。
過去の証拠のための dcp-jcs-v1 の検証は、ずっと残ります。候補の導入によって、
dcp-jcs-v1 の証拠が検証を通らなくなったり通るようになったりすることはありません。dcp-jcs-v1 のセキュリティの修正は
それぞれ単独で評価されます。
フェーズ 2 または 3 の前のゲート(要件。その状態は §18.4 の台帳にあります):
- コーパスの一致。 入力を定めるケースは、87 の元のベースラインのケースと、該当する設計の
ケースです。それらについて、すべての SDK と WASM は、バイト列の API を通じて、受け入れのケースで同じ
canonical_sha256を、拒否のケースで §6 の優先順位とオフセットを伴う同じクラスを返します。 廃止された v0.3 の深さの規則(depth_scope: "transport")を評価するケースはモデルを示すもので、受け入れの 要件ではありません。合成のバンドルのケースは、明示的な期待値を持つ本物の署名付きバンドルにならなければならず、 そのhistoricalパラメーターは各 SDK のパーサーの実際の観察に置き換えなければなりません。 それは決して証拠ではありません。 - オブジェクトの API の範囲。 解析済みのオブジェクトを受け取る API は、
needs_original_bytes: falseと 印の付いた拒否のケースを拒否し、trueと印の付いた拒否のケースは範囲外であると文書化します。 - 値についての出力の等価性。 定義域の各正確な値について、直接、または候補の
入力を通じて(リテラルから
dcp-jcs-v1のパーサーを通じてではなく)作った場合、どちらの正規化器も すべての SDK で同じバイト列を返します。 - バイト列からの入力の一致。 すべての SDK が、受け入れのケースから同じ値とバイト列を具体化します。
- 過去の読み取りは診断のまま。 リテラルをその正確な値と異なって読む過去のパーサーは、
独自の互換性の分析を伴う
dcp-jcs-v1の問題であって、ゲートではありません。 - 署名の交差マトリクス。 各生成側は、境界のペイロード(
±(2^53-1)、 U+E000 と U+1F600 を含むキー、文字列の先頭の U+FEFF、U+FFFD、U+2028、\u0000、深さ 64 まで入れ子にした単位)を持つ 候補のバンドルに署名し、すべての検証器がそれらを受け入れます。既存のdcp-jcs-v1の相互運用のマトリクスは緑のままです。 - 陰性のマトリクス。 各クラスの欠陥を、有効な候補のバンドルにバイトのレベルで注入すると、
署名を確認する前にそのクラスで拒否されます。同じ欠陥が
dcp-jcs-v1のバンドルにあれば、 現在の判定が保たれます。 - 選択、優先順位、ポリシー。 §6 と §7 のテストがすべての SDK で実行され、各検証が 1 つのプロファイルと 1 つの経路を使うことを計測して確認します。
- 過去の経緯。 新しい入力を導入した状態で、
dcp-jcs-v1の経路は、既存のベクターと適合性のスイートについて 各 SDK で現在の判定を返します。 - コスト。 前後で測り、埋め合わせのために何も緩めません。
10. コーパスとラボのツール¶
| ファイル | 内容 |
|---|---|
baseline-corpus.json |
欠陥が 1 つの 87 ケース(受け入れ 42、拒否 45、そのうち 6 は UTF-8 でないバイト列)、プロファイルの選択 10 ケース、ポリシー 3 ケース。承認されたリビジョン 2 のコピーで、proposal と provenance のフィールドだけが異なる。その domain.max_depth_scope は過去の表現(エンベロープを含む入力全体での深さ)を保っているが、corpus.json が scope_revisions に記録しているとおり、I4 がそれに取って代わる(単位のルートからの深さ)。どのケースも変わらない。すべてのベースラインのケースはエンベロープのない単位である |
corpus.json |
187 の設計のケース:複数の欠陥の並べ替え(54)、正確な数値(20)、エンベロープの有無での深さ(12)、伝送(19)と伝送のフェーズ(12)、選択(23)、入力(3)、過去のパーサー(8)、ポリシー(5)、設定(9)、移行(9)、そして合成のバンドルでのベースラインの選択とポリシーの 10 + 3 ケース。87 のベースラインのケースを ID と入力のハッシュで参照する |
tools/canonicalization-lab/model.py |
設計モデル:伝送からの抽出、§6 の優先順位を持つ反復的なバイトのスキャナー、N4、出力の規則、選択とポリシー、そしてハッシュの確認がペイロードのハッシュ、監査チェーン、マニフェストの署名の代わりとなる合成のバンドルの経路。実行時の動作は承認されたモデルのもの(承認されたファイルの SHA-256 は ab172c5f…)で、docstring は公開の経路と、想定する最後の重複の規則を明確にする。合成のコミットメントのために SHA-256 を計算し、何にも署名せず、何も検証しない |
tools/canonicalization-lab/generate_corpus.py |
corpus.json を書く。期待値は、それぞれが適用する規則(why)とともに手で書かれ、モデルを決してインポートしない |
tools/canonicalization-lab/run.py |
完全性、新しさ、妥当性、網羅性を確認し、274 のケースすべてでモデルを実行し、24 のネガティブコントロールを実行する |
バンドルのケースは最小限の合成のスキーマ(マニフェスト、intent、audit_entries、
signature.manifest_hash)を使い、その manifest_hash が複合署名の代わりになります。スキャナーがたどれない
単位について、SDK の現在のパーサーが何をするかは各ケースのパラメーター(historical)であって、
測定ではありません。
ランナーは次を確認します。 ベースラインのハッシュとその 87 のケースの参照、各ケースの入力のハッシュ、
コーパスがバイト単位で再生成されること、有効な状態とクラス、一意な ID(ベースラインに対しても)、
宣言されていない繰り返しの入力がないこと、値の層の順序付きの 20 組、各クラスとグループ、
各ベースラインの選択とポリシーのケースの網羅。実際の結果はすべて、コーパスの実行と各コントロールで
検証され(状態、クラス、形式、モード)、モデルの失敗は拒否としてではなく、必ず MODEL_ERROR として
報告されます。
ネガティブコントロール(すべて検出されなければなりません):変更した 3 つの期待値、それぞれ独自の規則で
検出される 14 のデータの破損、古いコーパス、すべてのケースで失敗するモデル、4 つの設計の変異体(オフセットの
代わりにクラスの順序、文法より前の値の層、dcp-jcs-v1 への代替、エンベロープ全体での深さ)で、それぞれが
ちょうど自分のケースだけを壊すもの、そして変異のもとでだけ注入される 2 つの失敗と、未知のクラスで
ちょうど期待されるケースを壊す 1 つの変異体。この 3 つはすべて、検出されたものとして数えるのではなく、
キャンペーンを無効にしなければなりません。
11. 再現¶
Linux または macOS 上の Python 3.9 以降(ランナーは signal.SIGALRM と pathlib.Path.is_relative_to を使います。
Windows はサポートしません)で、標準ライブラリだけを使います。コマンドはチェックアウトのルートから実行します。
ほかのディレクトリからは、スクリプトに絶対パスを与えてください。出力は新しい一時ディレクトリに出るため、
何も上書きされません。ランナーは既存の出力のパスも拒否し、生成器は指示された場所に
書きます。
out=$(mktemp -d)
python3 -I tools/canonicalization-lab/generate_corpus.py "$out/corpus.json"
cmp "$out/corpus.json" docs/proposals/canonicalization-candidate/corpus.json
python3 tools/canonicalization-lab/run.py --out "$out/run.json"
python3 tools/canonicalization-lab/run.py --controls --out "$out/controls.json"
期待される結果:274/274 cases as expected (87 r2 + 187 design)、すべてのコントロールが CAUGHT、終了コード 0。
終了コード 1 はケース、結果、コントロールのいずれかが異なること、2 はデータが無効であることを意味します。
12. これが示すこと、示さないこと¶
| 設計モデルが示すもの | 行っていないこと |
|---|---|
| 複数の欠陥を持つ 54 の文書と 12 のエンベロープでの、オフセットを伴う全体の優先順位 | フェーズや既定値の変更:§18 の生成側は実験的でオプトイン |
| 単位、伝送、エンベロープからの独立性 | 統合やサーバーでのバイト列の API |
| 合成のバンドルでの、選択、ポリシー、再試行がないこと | 定義域全体での出力の等価性の証明(§18.4 のゲート 3 はサンプルで示している) |
| 候補の経路がパーサーの修復に依存しないこと | 測った単位を超える過去の読み取り:tests/interop/candidate/phase2-adapter-expectations.json は、過去のアダプターが決める場合の本物のデコーダーの読み取りを 160 件(16 単位 × 10 アダプター)記録している。それはその単位についてだけの証拠である |
| 合成のバンドルのハッシュの確認 | dcp-jcs-v1 のバンドルのすべての欠陥が判定を保つことの証明:§18.5 は、エンベロープのない単位についてだけ、2 つの基準で 18 の位置にある単位の 8 つのクラスを抽出している |
委譲が、§16、§17、§18.5 のケースを超えて、またはエンベロープやサーバーについて、各 SDK の dcp-jcs-v1 の判定を保つこと |
13. 未解決の問い¶
dcp-jcs-v1の判定が保たれるかどうかは、過去のパーサーが最後の重複の規則でプロファイルの経路を読むことに 依存しており、実装の前に、実際の検証器の各入口の経路で測らなければなりません。 §16、§17、§18.5 は、エンベロープのない単位について、各 SDK の組み込みのアダプターでそれを測っています。 型付きの構築用のデコーダーは、検証器が使うデコーダーとは限りません。オブジェクトの API では、 呼び出し元や統合のバイト列からオブジェクトへのデコーダーがその経路の一部です。それは BOM を捨てたり、 不正な UTF-8 を修復したり、重複したメンバーを失ったり、検証の前にボディを拒否したりすることがあります。アダプターは その既存の経路を明示的に保たなければならず、共通のデコーダー 1 つで置き換えても過去との一致は成り立ちません。- バイトのレベルの伝送の契約は、あいまいなエンベロープについて結果を変えるため、独自の 互換性の注記が必要です。§18.5 はエンベロープの境界のケースを 3 つ記録していますが、どのサーバーとも等価性は主張しません。
- プロファイルをまたいだ監査チェーンの連続性、マニフェストのないアーティファクトのプロファイル、A2A は この設計の範囲外です。
14. 参考文献¶
- RFC 8259 §4(一意の名前)、§6(相互運用可能な数値の範囲)、§8.1(BOM)、§8.2(孤立したサロゲート)。
- RFC 7493(I-JSON)§2.1–§2.3。
- RFC 8785 §3.1、§3.2.2、§3.2.3(UTF-16 によるキーの順序。このプロファイルは使わない)。
spec/CANONICALIZATION_PROFILE.md(dcp-jcs-v1、変更なし)。
15. SDK の実験的な入力(フェーズ 1)¶
SDK の実装計画のフェーズ 1(§9 のフェーズではありません)は、各 SDK に、1 つの単位のための実験的でオプトインの
入力を加えます。規範的ではなく、既存の経路や既定の経路はそれを呼びません。呼ぶのはオプトインした呼び出し元だけです。
dcp-jcs-v1 の関数、既定値、署名者、検証器は何も変えません。入力自体は
プロファイルを読まず(§16 のルーターが読みます)、何も出力しません。生成側はフェーズ 4(§18)で加わりました。
| SDK | API |
|---|---|
| TypeScript | experimentalCandidateIngress(bytes: Uint8Array)、@dcp-ai/sdk がエクスポート |
| Python | dcp_ai.v2.experimental_candidate_ingress.experimental_candidate_ingress(data)、dcp_ai.v2 からは再エクスポートされない |
| Go | v2.ExperimentalCandidateIngress(input []byte) |
| Rust | dcp_ai::v2::experimental_candidate_ingress::experimental_candidate_ingress(&[u8]) |
| WASM | Rust のバインディングの wasm_experimental_candidate_ingress と、@dcp-ai/wasm の DcpWasm.experimentalCandidateIngress(bytes) |
すること。 1 つの単位の元のバイト列を受け取り、§6.1–§6.2 の優先順位とオフセットで §3.1–§3.3 を適用します。受け入れた場合は、正確な値、その正規のバイト列(§3.4)、その SHA-256 を返します。WASM のラッパーは値ではなく、バイト列とハッシュを返します。拒否は結果であり、 そのクラスとバイトのオフセットを伴います。引数の型の誤りと内部のエラーは別に報告され、拒否として 報告されることはありません。
しないこと:
- 伝送から単位を抽出する(§5、§6.3);
- プロファイルを選んだり、ポリシーを適用したりする(§6.4 の手順 1、5、6、§7);
dcp-jcs-v1に委譲する;- 何かを検証、署名、受け入れる。
テスト。 4 つの SDK(TypeScript、Python、Go、Rust)のそれぞれが、保存された 期待値(クラスとオフセット、または正規のハッシュ)に対して次のケースを実行します:
- 87 のベースラインの単位;
corpus.jsonのエンベロープのない 81 の文書のケース。
4 つのそれぞれは、受け入れたすべての値について、その dcp-jcs-v1 の正規化器が同じバイト列を返すことも
確認し、焦点を絞った例を加えます:不正な UTF-8、BOM、エスケープを通じた重複、
__proto__、長い数値のリテラルと飽和する数値のリテラル、サロゲートの組、そして遅い文法のエラーがある場合とない場合の
2 万段です。
WASM のテストは、@dcp-ai/wasm のラッパーを通じて本物の Rust のバインディングを同じ 168 のケースで実行し、
クラスとオフセット、または正規のバイト列とハッシュを比べます。値は得られないため、dcp-jcs-v1 との
比較はしません。JS/WASM の境界も確認します:
- バイト列は変わらずに Rust に届く(不正なバイト、BOM、NUL のエスケープ、より大きなバッファーのビュー);
- 2 万段の単位が返ってくる;
Uint8Arrayでない引数はTypeErrorになる。
すべての SDK で、77 のバンドルのケースと 29 のエンベロープのケース(廃止された深さの規則を含む)は 後のフェーズに属します。数えるだけで、実行はしません。
ゲート。 これは単位のケースについてだけの、§9 のゲート 1、3、4 に向けた証拠です。10 のゲートのどれも これで満たされることはなく、候補は無効のままです。
16. SDK の実験的なルーター(フェーズ 2)¶
SDK の実装計画のフェーズ 2 は、各 SDK に実験的でオプトインのルーターを加えます。単位を抽出し
(§5、§6.3)、プロファイルを読み(§7)、決定まで §6.4 を適用します。拒否する、dcp-jcs-v1 に委譲する、
または候補の経路を選ぶ、のいずれかです。規範的ではなく、既存の経路や既定の経路はそれを呼びません。呼ぶのは
オプトインした呼び出し元だけです。dcp-jcs-v1、その検証器、すべての既定値は変わりません。candidate は受け入れでは決してありません。それを検証するのはフェーズ 3 です。候補を検証したり
署名したりするものはありません。
| SDK | API |
|---|---|
| TypeScript | createExperimentalCandidateRouter(config).route(bytes)、experimentalCandidateExtractUnit、experimentalHistoricalAdapters |
| Python | dcp_ai.v2.experimental_candidate_router:create_router、extract_unit、JSON_LOADS_BYTES、JSON_LOADS_STRICT_DECODE |
| Go | NewExperimentalCandidateRouter(cfg) と Route、ExperimentalCandidateExtractUnit、ExperimentalHistoricalEncodingJSON |
| Rust | v2::experimental_candidate_router:CandidateRouter::new と route、extract_unit、HistoricalAdapter::serde_json_from_slice |
| WASM | バインディング wasm_experimental_candidate_route と _resume の上の DcpWasm.createExperimentalCandidateRouter、そして experimentalWasmHistoricalAdapters |
設定。 伝送(bare または envelope)、受け入れるプロファイル、過去のアダプターは
必須で、どれにも既定値はありません。
- ルーターを作るとき、どの入力よりも前に、厳格な型で検証されます。
- 無効な設定は設定のエラー(
POLICY_INVALIDまたはCONFIG_INVALID)であって、データの 拒否では決してありません。 - ルーターは非公開のスナップショットを保持するため、後で呼び出し元のオブジェクトを変えても何も変わりません。
結果。
reject: クラス(伝送のクラス、スキャナーのクラス、PROFILE_UNKNOWN、またはPROFILE_NOT_ACCEPTED) とそのオフセット。offsetは単位からの相対値、transport_offsetは入力の中のものです。v1_path: 単位、警告(D7)、過去のアダプターが返したもの。- そのプロファイルは常に
dcp-jcs-v1です。フィールドのないマニフェストはdcp-jcs-v1のもとで作られたものです。 profile_sourceが理由を示します:field、absent、またはスキャナーがたどれない単位の場合のhistorical。candidate: 単位、その値、その正規のバイト列。WASM のラッパーは、フェーズ 1 と同じく、正規のバイト列と そのハッシュを返しますが、値は返しません。
名前は SDK の間で、各言語の流儀で対応しています:TypeScript と WASM のラッパーでは profileSource、transportOffset、
canonicalSha256、Python、Rust、WASM のバインディングでは profile_source、transport_offset、
canonical_sha256、Go では ProfileSource、TransportOffset、
CanonicalSHA256 です。
過去のアダプター。 アダプターは 1 つの本物のデコーダーを再現し、ルーターはそれに最大 1 回、 §6.4 が必要とする場合にだけ問い合わせます:
- スキャナーがたどれない単位について決めるため;
- 委譲の値を作るため。
その読み取りが候補を選ぶことは決してなく、その結果は本物のデコーダーが返したもので、候補の規則で
浄化されません。NaN、無限大、孤立したサロゲートは、そのデコーダーが保持する場合にだけ保持されます。
json.loads は NaN と 1e999 を受け入れ、JSON.parse は 1e999 に対して Infinity を返し、どちらも孤立したサロゲートを保持します。
encoding/json と serde_json は 1e999 を拒否します。WASM の w1 の経路では、JSON.stringify が Infinity を
null に変え、孤立したサロゲートを再びエスケープし、serde_json がそれを拒否します。データを拒否する以外の形で
失敗するアダプターは、拒否ではなくアダプターのエラーです。
WASM のラッパーは、別々に測り、等価とは仮定しない、2 つの異なる経路を再現します:
w1: オブジェクトを、JSON.stringifyを通じて Rust へ;w2: テキストをバインディングへ。
そのバインディングは状態を持ちません。resume は自身の引数から決定点を再計算し、拒否か委譲でしか
終わりません。
テスト。 各 SDK と WASM は次のケースを実行します:
- 9 の設定のケース;
- 28 の文書のエンベロープのケース;
- たどれる 58 のバンドルのケース。
accept_v2とCOMMITMENT_MISMATCHはcandidateとしてだけ確認する; - 公開のフィクスチャー
tests/interop/candidate/phase2-adapter-expectations.json。スキャナーがたどれない 9 の単位と 7 の合成の単位について、各本物のデコーダーが返すものを、実際に実行して測って記録しています。コーパスのhistoricalパラメーターは証拠として使いません。
さらに次を確認します:
- 差分のない v1 の一致:エンベロープなし、
["dcp-jcs-v1"]、組み込みの各アダプターで、公開の署名付き バンドルとそれから生成した変種について; - フェーズ 1 のスキャナーに対する文法のウォーカー;
- 遅延、アダプターの契約、バイト列の所有。
ゲート。 これは選択と委譲についてだけの、§9 のゲート 1、8、9 に向けた証拠です。10 の ゲートのどれもこれで満たされることはなく、候補は無効のままです。
17. SDK の実験的な検証器(フェーズ 3)¶
SDK の実装計画のフェーズ 3 は、各 SDK に、元のバイト列の実験的でオプトインの検証器を加えます。 §16 のルーターでバイト列を 1 回振り分け、最大 1 つの検証器を実行します:
- 拒否ならどれも実行しない;
v1_pathなら、現在の V2 の検証器を、現在の呼び出し元が渡すのとまったく同じものに対して;candidateなら、マニフェストでちょうどdcp-jcs-v2を受け入れる、現在の V2 の検証器。
別のプロファイルでの 2 回目の試行はありません。規範的ではなく、既存の経路や既定の経路はそれを
呼びません。dcp-jcs-v1、既存の検証器、その既定値は変わらず、そのオブジェクトとテキストの API は
引き続き dcp-jcs-v2 を拒否します。生成側はフェーズ 4(§18)で加わりました。下のベクターはテスト専用の生成器が
署名しています。検証済みの候補のバンドルは、信頼もアドミッションも与えず、
何も認可しません。
| SDK | API |
|---|---|
| TypeScript | createExperimentalCandidateVerifier(config).verify(bytes, registry, policy?, options?) |
| Python | dcp_ai.v2.experimental_candidate_verify:create_verifier(...) と await verifier.verify(data, registry, policy=None, now_ms=None) |
| Go | NewExperimentalCandidateVerifier(ExperimentalCandidateVerifierConfig) と VerifyAt(registry, input, policy, now) |
| Rust | v2::experimental_candidate_verify:CandidateVerifier::new(config) と verify_at(input, policy, now_ms) |
| WASM | バインディング wasm_experimental_candidate_verify の上の DcpWasm.createExperimentalCandidateVerifier(config).verify(bytes, policy?) |
設定とパラメーター。 設定はルーターのもの(§16)です。伝送、受け入れるプロファイル、 過去のアダプターで、すべて必須で、どれにも既定値はありません。
- Go はアダプターを閉じた名前
encoding_jsonで指定し、そのデコーダーを自ら作るため、 エクスポートされたExperimentalHistoricalEncodingJSONを変えても何も変わりません。 - 検証のパラメーターは、各 SDK の V2 の検証器のもので、省略可能な暗号のポリシーも含め、 同じ既定値を持ちます。
結果。 経路、entered(none、dcp-jcs-v1、または dcp-jcs-v2)、そして検証器の結果をそのまま返します。
どれも実行されなかった場合、結果は null です。entered は開始された検証の経路を、そのポリシーの検証も含めて
示します。暗号の確認が実行されたことは示しません。検証器はまずポリシー、構造、
ハッシュ、セッションの確認で止まることがあり、その結果がそれを示します。
候補の経路。 これは、受け入れるマニフェストのプロファイルという 1 つの変更を加えた現在の検証器です。ハッシュ、
署名、ヘルパーはすべて現在のものです。候補が受け入れる正確な値については、dcp-jcs-v1 の正規化器が
候補のバイト列を返します(§3.4)。
- TypeScript、Python、Rust は正確な値を検証します。
- Go は候補の正規のバイト列を検証するため、そのパーサーが、候補が正規化したリテラルを読むことはありません。
委譲。 現在の検証器に、現在の呼び出し元が渡すのとまったく同じ入力を渡します。
- TypeScript、Python、Rust: アダプターが復号した値。
- 復号された
nullはデータであり、委譲されます。 - デコーダーがデータを拒否した場合は値がなく、何も実行されません(
entered: none)。 - Go: 単位のバイト列が
VerifySignedBundleV2Atに渡り、それが自ら解析します。 - WASM: 1 回の
wasm_experimental_candidate_verifyの呼び出し。 - デコーダーが必要なときは 1 回問い合わせ、決して検証しない
resumeが、拒否か委譲で 終わります。 - 委譲は、デコーダー自身の文字列を、
verifyBundleが送るポリシーの JSON とともにwasm_verify_signed_bundle_v2に渡します。w1では復号したオブジェクトのJSON.stringify、w2ではテキストです。 - 拒否したデコーダーは文字列を残しません。
- バインディングは V1 の動作を保ちます。V1 のバンドルはポリシーなしでは検証を通り、ポリシーがあれば拒否されます。
ベクター。 tests/interop/candidate/phase3-signed-vectors.json
には、18 の固定したベースと 57 のケースがあります。
- ベース: 16 の署名付きバンドル、V1 の適合性のバンドル、
null。 - 15 は TypeScript の SDK のテスト専用の生成器(生成側の API ではない)が署名しています。
- 16 番目は
B-reorderedで、B-v2と同じ署名付きバンドルを、メンバーを逆の順にし、 空白を加えたものです。 - ケース: ケースはベースにバイト列の編集を加えたものです。
- 期待値: 手で書いたもの。経路、アダプターの呼び出し、
entered、判定、各 SDK のエラーの 部分文字列で、デコーダーが異なる場合はアダプターごとの上書きがあります。
| グループ | ケース |
|---|---|
| 陽性 | 16:ハイブリッドとクラシカルのみ、1.0、1e2、-0、そして 1 の後に 800、801、5000 個の 10 進のゼロを続けて書いた整数、±(2^53-1)、エスケープ、メンバーの順序と空白、深さ 64、マニフェストの外のおとりのプロファイル、v1 の参照と並ぶ新しいチェーン、PQ のチェックポイント、__proto__ という名前のキー |
| どの検証器よりも前の拒否 | 17 |
| 候補の失敗 | 14、それぞれが名前の示す手順で |
| 委譲 | 10 |
生成器の --check は 2 つのことを検証します。固定したベース(そのハッシュ、ペイロードとマニフェストのハッシュ、
宣言されたプロファイル)と、すべてのケースと期待値です。TypeScript のテストは、意味的に無効なベースも含め、
16 の署名付きベースの 81 の署名を複合のプリミティブで検証します。
テスト。 各 SDK と WASM は次を実行します:
- どのケースよりも前に、ベクターがちょうど承認された 57 のケースの ID を 1 回ずつ持つことの確認。ID が 欠けている、繰り返されている、または未知であれば失敗する;
- 組み込みの各アダプターでの 57 のケース;
- 各委譲と直接の呼び出しとの一致;
- 実行される検証器が最大 1 つであることの計測による確認。テスト専用のプローブか数えるバインディングを使い、 検証を省く公開の API はない;
- 陽性の、コミットされた各値の正規のバイト列:単位、マニフェスト、4 つのペイロード、
監査エントリー、チェックポイント。候補の入力は、それぞれの
dcp-jcs-v1の正規のバイト列を、 同じ正確な値と同じバイト列で受け入れる; - 設定;
- 変異させたバッファー;
- 現在の API が引き続き
dcp-jcs-v2を拒否すること。
設計モデルとの対応。
| 設計モデル | フェーズ 3 |
|---|---|
accept_v2 |
verified: true と本物のマニフェストのハッシュを持つ候補の経路 |
COMMITMENT_MISMATCH |
検証器自身のエラーを伴う verified: false。複数を報告することがあり、その順序は規範的ではない |
| 拒否 | §16 の経路 |
| 委譲 | モデルが計算しない、現在の判定を記録する |
| — | 暗号の失敗(署名、ポリシー、鍵の有効性、セッション、チェックポイント):モデルに対応するもののない新しい期待値 |
ゲート。 フェーズ 3 では、§9 の 10 のゲートのどれも満たされたとは宣言されませんでした。台帳は §18.4 で、候補は 無効のままです。
- 向けた証拠:
- ゲート 1:合成のバンドルのケースを、本物の署名付きバンドルとして表し直したもの;
- ゲート 3:陽性のコミットされた値について;
- ゲート 7:署名付きの候補のバンドルに注入した欠陥は、どの検証器よりも前に拒否され、
dcp-jcs-v1のバンドルでは委譲された判定が現在のものになる; - ゲート 8:計測した 1 つの検証器。
- 満たされていない:
- ゲート 6、署名の交差マトリクス。生成側が必要で、ここでの署名付きバンドルはすべて 1 つのテストの 生成器から来ている;
- ゲート 2、9、10。それぞれ独自の実行が必要。
18. SDK の実験的な生成側(フェーズ 4)¶
SDK の実装計画のフェーズ 4 は、各 SDK と WASM に実験的でオプトインの生成側を加えます。それらは
新しい証拠を作ります。現在のものと同じように署名されたアーティファクトと、新しいマニフェストが
canonicalization_profile: "dcp-jcs-v2" に署名するバンドルです。規範的ではなく、既存の経路や既定の経路はそれらを呼びません。
dcp-jcs-v1、そのビルダー、署名者、検証器、そしてすべての既定値は変わりません。プロファイルは
npm の SDK 2.2.0 と WASM 2.1.0 を含め、実験的で明示的な選択が必要なままです。それらが作るバンドルは、信頼もアドミッションも与えず、何も認可しません。
| SDK | API |
|---|---|
| TypeScript | experimentalCandidateSignPayload(registry, context, input, keys) と experimentalCandidateSignBundle(registry, parts, signer, options) |
| Python | dcp_ai.v2.experimental_candidate_produce:sign_payload(registry, context, input, keys) と sign_bundle(registry, parts, signer, options)。呼び出し時に確認とコピーを行い、awaitable を返す |
| Go | ExperimentalCandidateSignPayload(registry, context, input, keys) と ExperimentalCandidateSignBundle(registry, parts, signer, options)、入力は ExperimentalCandidateBytes と ExperimentalCandidateHostValue |
| Rust | v2::experimental_candidate_produce:sign_payload(context, input, keys) と sign_bundle(parts, signer, options)、CandidateInput::{Bytes, Value} を使う |
| WASM | DcpWasm.experimentalCandidateSignPayload(context, input, keys) と experimentalCandidateSignBundle(parts, signer, options)。バイト列だけを受け取るバインディング wasm_experimental_candidate_sign_payload と wasm_experimental_candidate_sign_bundle の上にある |
入力。 各部分は次のいずれかです:
- バイト列: 元のバイト列で、何かがそれを解析する前に、フェーズ 1 の入力(§15)で確認されます。これは ほかから受け取った JSON のための方法です。パーサーが修復したり失ったりするものを保つのはバイト列だけです;
- ホストの値: 言語の正確な型に対する厳格な走査で確認され、確認の後に符号化されます。 値は、それが解析された元のリテラルを示せないため、パーサーがすでに修復した値は検出できません。
定義域の外のホストの値は、NUMBER_NOT_FINITE、NUMBER_NOT_INTEGER、
NUMBER_OUT_OF_RANGE、SURROGATE_UNPAIRED、UTF8_INVALID(Go)、DEPTH_EXCEEDED、TYPE_UNSUPPORTED、または
KEY_NOT_STRING(Python)で拒否されます。整数値の float、-0、そして TypeScript と WASM では BigInt が、
整数に正規化されます。ゲッターと toJSON は決して呼び出されません。構造体と外部の型は拒否され、変換されることはありません。
signPayload は、DCP のコンテキストのもとで、プロファイルなしで、1 つのアーティファクト {payload, payload_hash, composite_sig} に
署名します。ペイロードは最大 63 段で、アーティファクトが最大 64 段になるようにします。入力は
出力のバイト列を受け入れ、変えずに返します。
signBundle は正確な値の上でバンドルを組み立てます。部分は、アーティファクト、監査エントリー、省略可能な PQ の
チェックポイントで、それぞれバイト列か値です。
- 知らないメンバーは保持されます。ペイロード、エントリー、チェックポイント、マニフェストの外にあるものは 署名されないため、その完全性は主張されません。
- 受け取った証拠のラベルを付け替えたり再計算したりすることは決してありません。
payload_hashがそのペイロードのものでない アーティファクトは拒否され(COMMITMENT_MISMATCH)、チェーンはGENESISから始まり、つながっていなければなりません(CHAIN_NOT_GENESIS、CHAIN_BREAK)。 - 署名者は責任を負うプリンシパルでなければなりません(
SIGNER_MISMATCH)。 - セッションの開始が時計から刻まれることは決してありません。期限があれば
session_issued_atが必須で (SESSION_ISSUED_AT_REQUIRED)、日付は有効でなければなりません(SESSION_INVALID)。 - 空の監査証跡は
audit_count: 0と 64 個のゼロのルートを返します。 dualHash(既定では無効)は SHA3-256 のルートとhash_alg: sha256+sha3-256を加えます。created_atはすべての署名の外にあり、保護されていません。- どの署名よりも前に、単位全体が最大 64 段であることを確認します。
- §16 のルーターは、出力を
candidateとして振り分け、canonical_sha256は出力の バイト列の SHA-256 に等しくなります。
エラー。 この契約の拒否は、そのクラス、部分、JSON Pointer またはバイトのオフセットを伴い、
どの署名者も呼ばれる前に発生します(テストは署名者の呼び出しをゼロと数えます)。API の誤用は使い方のエラーです:
TypeError、ErrExperimentalCandidateUsage、または ProduceError::Usage。鍵、レジストリ、
プロバイダーのエラーは現在のままです。
現在のビルダーとの対比。 これらは dcp-jcs-v1 のビルダーのオプションではなく新しい API で、意図的に
異なります。明示的な日付、どこでも同じ dualHash の既定値(Go、Rust、WASM の v1 のビルダーは既定で
二次のルートを加えます)、そして正確な値の上での組み立てです。
18.1 交差マトリクス(tests/interop/candidate/phase4/)¶
5 つの生成側(TypeScript、Python、Go、Rust、WASM)が、公開されたオプトインの API で同じ入力のバイト列に署名します。
すべての利用側が、すべての出力を §17 の検証器で検証します。ランナーとその仕様は
tests/interop/candidate/phase4/ にあります。合成の鍵は実行ごとに
作られ、実行のディレクトリの外に書かれることはありません。
- 陽性: bytes と value のモードでの 12 の仕様(
S01–S12)に加え、リング:次の生成側が署名した アーティファクトから組み立てたS01。合わせて 115 の単位で、それぞれを 5 つの利用側が検証し、575 の結果になります。 次を扱います: - ハイブリッドとクラシカルのみの署名、二重のハッシュ、PQ のチェックポイント;
- ±(2^53−1);
- U+E000 と U+1F600 を含むキー;
- 文字列の先頭の U+FEFF、U+FFFD、U+2028、
\u0000; - 深さ 64;
- 署名されていない拡張のメンバー;
__proto__、constructor、toJSONという名前のメンバー;- 800 個と 5000 個の 10 進のゼロで書いた整数(バイト列);
1.0と-0.0(値)。- 陰性: 各生成側の新しい出力に対するバイトのレベルの 16 の編集を、すべての利用側が検証し、400 の結果になります。
- どの検証器よりも前に:BOM、不正な UTF-8、構文のエラー、孤立したサロゲート、重複、小数、 範囲外の数値、深さ 65、伝送のエラー、未知のプロファイル、受け入れられないプロファイル。
- 候補の経路で、そこで失敗するもの:変更したペイロード、変更したマニフェスト、反転したクラシカルまたは PQ の署名。
- V2-2 以降(すべての SDK でのスキーマ検証。
mainにあり、未リリース):未知のメンバーが閉じたオブジェクトにあるS09の 50 の結果は、厳密なスキーマ診断とともに拒否されます。実行は現在、陽性 525 と陰性 450、合計 975 の結果を期待します。575 と 400 はフェーズ 4 の完了時の数です。フェーズ 4 の README を参照してください。 - ランナーの確認:
- 975 の結果、手順、フィールドの正確な集合;
- 新しさ:実行 ID、日付、ファイルの時刻;
- 各利用側が観測したデコーダーの呼び出し(BOM、UTF-8、構文では 1、それ以外は 0);
- 各仕様について、すべての生成側から同じ
manifest_hash、そして ML-DSA の署名の値(ランダム化される)を 除く同じ単位。マスクするのはその既知の位置だけ; - すべての SDK が導出した同じ鍵の ID;
- プロセスグループ全体を強制終了する期限;
--self-testはこれらの拒否のそれぞれを確認する。
18.2 ホストの値(ゲート 2)¶
コーパスの各 ID は、言語ごとに次のように分類されます:
- R: バイト列のクラスで、正確に表される;
- T: すでに変換された値としてだけ表され、そのクラスは変わることがある;
- P: まずパーサーが拒否する;
- N: 表せない。
R と T のセルはすべてその SDK でテストされ、P と N は文書化されます。needs_original_bytes: false という印は、
パーサーがすでにそのケースを拒否できることを意味するだけです。
| ID | バイト列 | TS / WASM | Python | Go | Rust |
|---|---|---|---|---|---|
n-two53, n-1e20, n-1e21, n-fraction, s-depth-65, s-depth-129 |
コーパスのとおり | R | R | R | R(深さは直接構築) |
n-two53-plus-one, n-neg-two53-plus-one, n-int64-max, n-sci-over |
NUMBER_OUT_OF_RANGE |
BigInt なら R、number なら T(丸められ、まだ範囲外) | R(int) | R(int64) | R(i64) |
n-overflow (1e400) |
NUMBER_OUT_OF_RANGE |
BigInt なら R、number なら T(Infinity:NUMBER_NOT_FINITE) |
R(int)、float なら T(inf) |
整数としては N、json.Number のリテラルとしては R、float64 なら T(+Inf) |
N |
n-huge-exponent(5000 桁の指数) |
NUMBER_OUT_OF_RANGE |
整数としては N(具体化できない)、T(Infinity) |
N、T(inf) |
json.Number のリテラルとしては R で、数を作らずに拒否される、T(+Inf) |
N |
n-nan, n-negative-infinity |
SYNTAX |
T(NUMBER_NOT_FINITE) |
T | T | N |
| 構文の 9 の ID(先頭のゼロ、プラス記号、裸の小数点、生の制御文字、末尾のカンマやデータ、2 つの値、空の入力、NBSP) | SYNTAX |
P | P | P | P |
n-huge-exponent の T のセルは、パーサーがやはり無限大に変える、より短いリテラル(1e99999)を使います。
true と印の付いた 22 のケースは値の範囲外のままで、それらについてはバイト列が方法です。
18.3 コスト(ゲート 10)¶
コストは、プラットフォームごとに 1 組の等価な組で測ります。両側は同じ鍵、ペイロード、セッション、
監査エントリーを使い、ランナーは測る前に出力でそれを確認します。同じ 4 つの payload_hash、
同じ nonce とセッションの日付、同じエントリーです。v1 のバンドルは各 SDK のビルダーと署名者から、
候補は生成側から来ます。
各操作は 3 回のウォームアップの後に 20 回実行され、プラットフォームごとに最大 60 秒で、ビルドは別に
計時されます。node tests/interop/candidate/phase4/run.mjs --cost で実行してください。1 台の
マシンでの 1 回の実行の中央値(ミリ秒)です(Apple M5 Pro、Node 22.15、Python 3.12、Go 1.26、Rust 1.93 release):
| プラットフォーム | v1 の生成 | 候補の生成 | 現在の検証 | v1 の検証(v1_path) |
候補の検証 |
|---|---|---|---|---|---|
| TypeScript | 40.3 | 48.1 | 20.2 | 20.7 | 32.0 |
| Python | 22.8 | 27.6 | 3.5 | 7.7 | 7.7 |
| Go | 3.2 | 7.0 | 2.1 | 2.9 | 2.5 |
| Rust | 2.3 | 3.0 | 0.7 | 0.9 | 0.8 |
| WASM | 4.1 | 4.8 | 1.5 | 2.1 | 1.4 |
限界。 これらの時間は正規化だけを測ったものではなく、改善も 後退も示しません:
- 出力が異なる。 v1 のバイト列は各 SDK の JSON のシリアライズ(Python のものは空白を含む)ですが、 候補のものは正規です。
- ビルダーが異なる。 Go、Rust、WASM の v1 のビルダーは二次のルートを加えますが、ここでの候補は 加えません。
- Go のエントリー。 v1 のビルダーは型付きのエントリーを受け取るため、その
AuditEvidenceV2は null のメンバーを落とします。Go の組の 両側は、それを通じて作り直した同じエントリーに署名します。 - 「現在の検証」に含まれるもの。 API がオブジェクトや値を受け取る場合は、バイト列の復号
(
JSON.parse、json.loads、serde_json::from_slice)を含みます。Go の API はバイト列を受け取り、自ら解析します。 - ばらつき。 中央値は同じマシンでも実行ごとに変わりました。たとえば、TypeScript の候補の 検証は、以前の実行では約 22 ミリ秒でした。
SLA はなく、埋め合わせのために何も緩めていません。
18.4 10 のゲートの台帳(§9)¶
この台帳は証拠を記録するもので、何も有効にしません。フェーズや既定値の変更にはそれ自体の決定が必要です。
| # | ゲート | 状態 | 証拠 | 限界 |
|---|---|---|---|---|
| 1 | コーパスの一致 | 満たした | §15:4 つの SDK での 87 のベースラインの単位と 81 のエンベロープのない設計のケース、そして WASM での同じ 168 のケース。§17:本物の署名付きバンドルとしての合成のバンドルのケース。§16:historical パラメーターの代わりの本物のデコーダーの読み取り |
v0.3 の深さの規則のケースはモデルを示すもので、要件ではない |
| 2 | オブジェクトの API の範囲 | §18.2 の範囲で満たした | §18.2:言語ごとにテストしたすべての R と T のセルで、それぞれ署名の前にそのクラスで拒否される。TypeScript、Python、Go、WASM はセルごとに署名者の呼び出しをゼロと数える。Rust のセルは署名できない鍵を使うため、署名者が呼ばれればプロバイダーのエラーとして現れる。数えたゼロの呼び出しは、その焦点を絞った単体テストにある | true と印の付いた 22 のケースと、P と N のセルは値の範囲外 |
| 3 | 値についての出力の等価性 | サンプルで満たした | §15:受け入れた値での dcp-jcs-v1 との比較。§17:陽性のコミットされた値。§18.1:5 つの生成側で等しい 115 の単位。§18.3:v1 の署名者と生成側からの同じペイロードのハッシュ |
コーパス、ベクター、マトリクスで示したもので、定義域全体で証明したものではない |
| 4 | バイト列からの入力の一致 | 満たした | §15、4 つの SDK と WASM で | 単位のケース |
| 5 | 過去の読み取り | ゲートではない | §16 がそれらを診断として記録する | — |
| 6 | 署名の交差マトリクス | 満たした | §18.1:5 × 5 とリング、975 中 975 の結果で、ゲートのすべての境界のペイロードを含む。dcp-jcs-v1 の相互運用のマトリクス(tools/interop-matrix、両方のシナリオ)は終了時に通る |
1 台のマシンでのローカルの実行。ワークフローは変更のたびに再実行する |
| 7 | 陰性のマトリクス | サンプルで満たした | 候補の側:§18.1、コーパスのすべてのクラスと、伝送とプロファイルのクラスが、どの検証器よりも前に拒否される、5 × 5、そして候補の経路での候補の失敗。dcp-jcs-v1 の側:§18.5、38 ケース(2 つの基準での単位の 8 つのクラスの 18 の変異と、2 つの制御)× 4 つの SDK と WASM の 10 の構成、380 件の比較。実験的な検証器は現在の結果を返し、両方がコミット済みの期待値と一致する |
抽出したクラスと位置で、普遍的な証明ではない。エンベロープのない単位だけで、エンベロープやサーバーについての等価性は主張しない。WASM は Node 上で動かし、バインディングの境界で測る |
| 8 | 選択、優先順位、ポリシー | 満たした | §16 と §17、計測した 1 つの検証器で | — |
| 9 | 過去の経緯 | 満たした | 終了時に、新しいコードを入れた状態で:適合性(V1 と V2、アドミッションのケースを含む)、各 SDK の全テストスイート、WASM のテスト(バンドルのベクターと V1 の検証を含む)、dcp-jcs-v1 の相互運用とアドミッションのマトリクスがすべて緑。フェーズ 1 から 3 のキャンペーンは繰り返していない |
1 台のマシンでのローカルの実行 |
| 10 | コスト | 満たした | §18.3 | 1 台のマシン、SLA なし、§18.3 の限界 |
18.5 dcp-jcs-v1 の側のゲート 7(tests/interop/candidate/gate7-v1-negatives.json)¶
ゲート 7 は 2 つのことを求めます。候補の側(候補のバンドルに注入した各クラスの欠陥が、どの検証器よりも前にそのクラスで拒否されること)は §18.1 と §17 にあります。
この節はもう一方の側です。同じ欠陥を dcp-jcs-v1 のバンドルにバイトのレベルで注入しても、そのバイト列が §17 の実験的な検証器を通ったときに現在の判定が保たれることです。
対象はエンベロープのない単位だけです。
コーパス。 フィクスチャは、フェーズ 3 のベクターの凍結した 2 つの基準を参照とハッシュで再利用します。B-v1(マニフェストが dcp-jcs-v1 を指定)と B-absent(そのフィールドがない)です。
何も署名し直しません。同じ 18 のバイトのレベルの変異を両方の基準に適用します。
| ID | クラス | 位置 |
|---|---|---|
| M01 | BOM |
単位の前 |
| M02, M03 | UTF8_INVALID |
署名されないメンバー、署名された意図 |
| M04, M05 | SYNTAX |
末尾のカンマ、途中で切れた単位 |
| M06, M07 | SURROGATE_UNPAIRED |
署名されないメンバー、署名された意図 |
| M08, M09, M10 | DUPLICATE_KEY |
署名されないメンバー、最後が同じ値の署名された意図、最後が別の値の署名された意図 |
| M11, M12, M13 | NUMBER_NOT_INTEGER |
署名されないメンバー、署名されたポリシーの決定、監査のエントリー |
| M14, M15 | NUMBER_OUT_OF_RANGE |
署名されないメンバーの 2^53+1、署名されたポリシーの決定の 2^53+1 |
| M16, M17, M18 | DEPTH_EXCEEDED |
署名されないメンバーに 64 の入れ子の配列(レベル 65)、199(レベル 200)、署名された risk_score の代わりに 64 |
これで 38 ケース(18 の変異 × 2 つの基準に、制御としての 2 つの基準を加えたもの)になります。 各ケースは 10 の構成それぞれについての期待値を持ち、5 つの実装にまたがります。TypeScript、Python、Go、Rust の SDK と、Node 上(ブラウザーではない)の WASM パッケージです。
| 実装 | 構成(組み込みのアダプターまたは経路) |
|---|---|
| TypeScript | textDecoderJsonParse, bufferUtf8JsonParse |
| Python | json_loads_bytes, json_loads_strict_decode |
| Go | encoding_json |
| Rust | serde_json_from_slice |
| WASM | w1TextDecoderJsonParse, w1BufferUtf8JsonParse, w2TextDecoder, w2BufferUtf8 |
エンベロープのない比較は 380 件です。エンベロープの 3 ケース(G7E-1 から G7E-3)は別の境界の節で、さらに 30 件の確認になり、等価性は主張しません(後述)。
2 つの経路。 各ケースと構成について、2 つの経路が同じバイト列、同じ時計、既定の検証器ポリシーを受け取ります。
- エンベロープなしで
["dcp-jcs-v1"]を受け入れる、§17 の実験的な検証器。 - 同じ実装の現在の経路で、テストに書き出したもの。本物のデコーダー、次に現在の V2 の検証器です。
アダプターのオブジェクトやルーターを決して通りません。Go では検証器がバイト列を自分で解析し、WASM の
w1ではJSON.parseの後にverifyBundle、w2ではテキストがそのままバインディングに渡ります。
判定の仕方。
- 2 つの結果は、その実装の結果のすべての宣言されたフィールドで深く等しくなければなりません。新しいフィールドは、 宣言されるまでテストを失敗させます。
- 両方がコミット済みの期待値と一致しなければなりません。期待値は、経路(結果、クラス、プロファイルの出所、警告、
デコーダーが成功したかどうか)、デコーダーの呼び出し、入った検証器、現在の経路の結果、そして名前付きの共有の形を
通じて
verified、エラーの部分文字列とエラーの正確な数、警告、モード、ティア、manifest_validを固定します。 - 期待値はパーサーと検証器から推論したもので、出力から生成したことはありません。各形がその理由を述べています。
推論した WASM のエラー文の 1 つは、
serde_jsonのコードから説明したうえで修正しました。\uが続かない先頭の サロゲートは "unexpected end of hex escape" になります。2 つの経路は同じ文を返しました。
現在の経路の結果。
verified_result:検証器が結果を返した。host_decode_error:どの検証器よりも前に動くホストのデコーダーがバイト列を拒否した(TypeScript と WASM のw1:SyntaxError、Python:JSONDecodeErrorまたはUnicodeDecodeError、Rust:serde のカテゴリー)。in_band_parse_error:入力を自分で解析する検証器が、解析の失敗を結果の中で返した(Go と、w1とw2の WASM のバインディング)。厳密な形で、かつ同じパーサーが同じ入力を拒否する場合にだけ数え、そうでなければ 検証器のエラーです。- 検証器の例外、パニック、エラーのエンベロープ、そしてハーネスの失敗は、決して一致にも拒否にもなりません。
解析が失敗したとき、実験的な経路は 3 通りに終わりえます。どれになるかはケースごとにフィクスチャが示します。
- 拒否され、検証器なし(スキャナーが辿れない単位を、そのデコーダーが拒否した場合)。
- デコーダーの失敗とともに委譲され、検証器なし(Rust の、孤立したサロゲートまたは 200 レベル)。
- 委譲され、検証器がなお解析して結果の中で失敗する(Go と、M06、M07、M17 の WASM)。
制御。
- 実際に入った検証器は、結果から読むのではなく観測します。TypeScript と Go のテスト用のプローブ、Python の
モジュールの参照、Rust の
verify_routedのプローブ、そして WASM ではバインディングの境界で数えたバインディング (verify 1 回、デコーダーの呼び出しごとに resume 1 回、dcp-jcs-v1に入るときにだけ委譲 1 回)です。dcp-jcs-v1への入りは 0 回か 1 回だけを受け入れ、候補への入りや 2 回目の入りは失敗になります。 - Go、Rust、WASM では、公開の検証器が計測した経路と同じ結果を返さなければなりません。
- 入力のバッファーは各呼び出しの後で変わってはなりません。
- 2 つの制御は検証に成功しなければならず、失敗した制御や存在しない制御は、その基準のすべてのケースを無効にします。
- 各テストは期待したすべての比較が実行されたことを確認し、1 つも実行されなければ失敗します。
- 自己テストは判定が失敗しうることを示します。後の時刻、1 つ変えたエラー、両側での検証器の例外、余分な入りや 欠けた入り、そして 2 つの経路がすべてを拒否する、またはすべてを受け入れる偽物です。
- WASM のバインディングは
Date.nowを読みます。両方の経路の各呼び出しは、それをフィクスチャの時刻に固定して実行し、 例外の後も含めてfinallyで元に戻します。 - チェッカー
gate7-v1-negatives.pyは各入力を作り直し、 フィクスチャを厳密に確認します。正確な ID と構成、すべてのハッシュ、各変異のクラス・位置・編集の同一性、 構成ごとに閉じたデコーダーのエラーの種類、各期待値の一貫性です。その陰性の制御はtest_gate7_v1_negatives.pyです。
境界:エンベロープは別扱い。 G7E-1 は B-v1 を有効なエンベロープに入れたもので、エンベロープのない制御と同じフィールドで検証に成功しなければなりません。
G7E-2(2 つ目の signed_bundle メンバー)と G7E-3(エンベロープの前の BOM)は伝送が拒否し、デコーダーの呼び出しも検証器への入りもありません。
エンベロープを読む過去の SDK の API はなく、参照サーバーは最後の重複を採ります。どの伝送ともサーバーとも等価性は主張しません。
構成、伝送、プロファイルのクラスは、§16 と §17 がすでに定めて確認している境界にとどまります。
再現。 テストのファイルは TypeScript、
Python、
Go、
Rust、
WASM です。Python のテストには開発用の追加パッケージ付きで
インストールした SDK が、WASM のテストには先に npm run build が必要です。
python3 -I tests/interop/candidate/gate7-v1-negatives.py --check
python3 -I tests/interop/candidate/test_gate7_v1_negatives.py
(cd sdks/typescript && ./node_modules/.bin/vitest run src/__tests__/experimental-candidate-gate7.test.ts)
(cd sdks/python && python -m pytest tests/test_experimental_candidate_gate7.py)
(cd sdks/go && go test ./dcp/v2 -run TestGate7)
(cd sdks/rust && cargo test --all-features --lib gate7_tests)
(cd sdks/wasm && node test/experimental-candidate-gate7.mjs)
CI では、適合性のジョブがチェッカーとその制御を、各 SDK のジョブがそれぞれのファイルを実行します。 完了時点で、380 件の比較と 30 件の境界の確認はすべて合格し、どの経路も食い違いませんでした。
制限。
- 抽出したクラスと位置:2 つの基準で 18 の位置にある 8 つのクラス。すべての欠陥やすべてのバンドルについての 証明ではなく、ゲート 3 も引き続きサンプルでのものです。
- エンベロープのない単位だけが対象です。エンベロープ、サーバー、構成・伝送・プロファイルのクラスは範囲外です。
- 現在の判定は記録するだけで評価しません。実装の間で異なる場合、それは
dcp-jcs-v1の診断(ゲート 5)です。 - WASM はブラウザーではなく Node 上で動かし、バインディングの境界で測ります。モジュール内部の暗号の呼び出しは 数えていません。
- 候補は実験的でオプトインのままです。
dcp-jcs-v1とすべての既定値は変わらず、何も有効にしません。