.cgfevidence バンドル形式
.cgfevidence ファイルは、単一・自己完結・署名済みのコンプライアンス成果物です。zstd 圧縮された tar アーカイブであり、固定の内部構成と Ed25519 + RFC 3161 暗号を持ちます。任意の CGF リーダーは、バンドル自身とトラスト・ストアだけでオフライン検証できます。
ディスク配置
dossier.cgfevidence ← tar + zstd
├── manifest.json ← 形式 / 版 / ハッシュ
├── graph.json ← 決定論的・内容アドレスのグラフ
├── claims.json ← クレーム・パック結果(構造化)
├── narrative.md ← グラフ + クレームからレンダリング
├── signatures/
│ ├── ed25519-ops@acme.sig ← signed-payload.bin に対する分離署名
│ └── ed25519-cto@acme.sig
├── signed-payload.bin ← 署名対象の正準バイト列
└── timestamp/
└── freetsa.tsr ← RFC 3161 TimeStampToken(任意)
signatures/ と timestamp/ を除くすべてが manifest.rootSha256 にハッシュされます。署名は signed-payload.bin を覆い、これは manifest.json の正準(キー整列・LF 終端)JSON 符号化です。これにより、署名すべきハッシュも検証すべきハッシュも一つで済みます。
manifest.json
{
"format": "cgf",
"version": "1.0",
"rootSha256": "9f3a…d27e",
"createdAt": "2026-04-12T09:14:22Z",
"ingestor": {
"name": "@daitai/cgf",
"version": "1.0.0-rc.1"
},
"files": [
{ "path": "graph.json", "sha256": "1e88…5a02", "bytes": 184211 },
{ "path": "claims.json", "sha256": "73c0…b119", "bytes": 41098 },
{ "path": "narrative.md", "sha256": "ab4f…0c7d", "bytes": 22440 }
],
"claimPacks": [
{ "id": "eu-ai-act-high-risk", "version": "1.0.0", "result": "fail" },
{ "id": "gdpr-art-30", "version": "1.0.0", "result": "pass" },
{ "id": "soc2-cc", "version": "1.0.0", "result": "pass" }
]
}
rootSha256 は sha256(canonicalize({ files, claimPacks, ingestor, createdAt })) です。いずれかのファイル内の 1 バイトでも変われば、rootSha256 が変わり、すべての署名が失敗します。
署名スキーマ
署名は signed-payload.bin に対する Ed25519 です。ファイル名は情報目的のもので、束ねるのは埋め込まれた keyId です。
// signatures/ed25519-ops@acme.sig.json
{
"alg": "Ed25519",
"keyId": "ops@acme",
"pub": "9c4d…ef10", // 32 バイト生公開鍵, hex
"sig": "2c7b…f441", // 64 バイト署名, hex
"over": "signed-payload.bin",
"ts": "2026-04-12T09:14:22Z"
}
複数署名者バンドルは複数の *.sig.json ファイルを含むだけです。何人必要か、各人がトラスト・ストアに在籍する必要があるかは、信頼ポリシーが決定します。
タイムスタンプ (RFC 3161)
--tsa <url> で構築された場合、タイムスタンプ局からの応答は DER 符号化された TimeStampToken としてそのまま保存されます:
timestamp/freetsa.tsr ← 生の RFC 3161 TimeStampToken (DER)
timestamp/freetsa.json ← 解析済みの補助コピー
解析済みコピー:
{
"alg": "RFC3161",
"tsa": "https://freetsa.org/tsr",
"time": "2026-04-12T09:14:25Z",
"hash": { "alg": "sha256", "value": "9f3a…d27e" }
}
hash.value は manifest.rootSha256 と等しくなければなりません。これにより、TSA の「時刻 T 以前に存在した」証言がまさにこのバンドルに束ねられます。
検証アルゴリズム
準拠リーダーは次を行わなければなりません:
- バンドルをメモリ上で展開・解凍する。
manifest.filesの各エントリのsha256を再計算し比較する。rootSha256を再計算しmanifest.rootSha256と比較する。- 各署名について、埋め込みの
pubを用いてsigned-payload.binに対する Ed25519 検証を行う。 timestamp/*.tsrが存在すれば解析し、TSA の CMS 署名を検証し、messageImprintがrootSha256と一致することを確認する。- 有効な
TrustPolicy(トラスト・ストアとポリシー・プリセット 参照)を適用し、passまたは構造化された違反の一覧を出力する。
ステップ 1–5 は暗号操作であり、どのマシンでも同一です。ステップ 6 はポリシーであり、検証側組織のリスク許容度を反映します。
例: 最小の有効バンドル
demo.cgfevidence
├── manifest.json
├── graph.json
├── claims.json
├── narrative.md
├── signed-payload.bin
└── signatures/
└── ed25519-alice.sig.json
これだけ — TSA なし、署名者は一人。タイムスタンプを要求しない任意のポリシーに対して signed, untimestamped, 1/1 signers trusted として検証されます。