ホーム / コード
例示・非規範
コード事例
VAPが組み合わせる基礎要素の最小・軽依存の実装例:正規化ハッシュ、チェーン化イベント、 Ed25519署名、Merkle証明、RFC 3161アンカリング。フィールド名は例示であり、規範スキーマは 仕様を、参照実装は GitHubを参照。
1 · イベントのかたち
{
"event_id": "0198f3a2-7c1e-7d2a-9b1e-2f6a0c9d4e11",
"event_type": "DECISION_MADE",
"occurred_at": "2026-08-19T02:14:07.412Z",
"actor": { "actor_id": "model:risk-scorer", "actor_class": "AI_SYSTEM" },
"policy": { "policy_id": "POL-2026-014" },
"payload_hash": "sha256:9f2b…c41a",
"prev_hash": "sha256:5d80…7e0c",
"event_hash": "sha256:b7a1…22f9",
"signature": { "alg": "Ed25519", "key_id": "op-2026-01", "value": "…" }
}
2 · イベントのチェーン化と署名(Python)
正規化JSON → SHA-256 → prev_hash チェーン → Ed25519署名
(pip install cryptography)。
"""Illustrative, non-normative. Consult VAP v1.2 for the normative schema."""
import json, hashlib
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
def canonical(obj) -> bytes:
return json.dumps(obj, sort_keys=True, separators=(",", ":"),
ensure_ascii=False).encode()
def sha256_hex(b: bytes) -> str:
return "sha256:" + hashlib.sha256(b).hexdigest()
key = Ed25519PrivateKey.generate()
def append_event(chain: list, body: dict) -> dict:
prev = chain[-1]["event_hash"] if chain else "sha256:" + "0" * 64
core = {**body, "prev_hash": prev}
event_hash = sha256_hex(canonical(core))
sig = key.sign(event_hash.encode()).hex()
event = {**core, "event_hash": event_hash,
"signature": {"alg": "Ed25519", "value": sig}}
chain.append(event)
return event
def verify_chain(chain: list) -> bool:
prev = "sha256:" + "0" * 64
for ev in chain:
core = {k: v for k, v in ev.items()
if k not in ("event_hash", "signature")}
if ev["prev_hash"] != prev: return False
if sha256_hex(canonical(core)) != ev["event_hash"]: return False
prev = ev["event_hash"]
return True
3 · Merkleルートと包含証明(Python)
import hashlib
def h(b: bytes) -> bytes: return hashlib.sha256(b).digest()
def merkle_root(leaves: list[bytes]) -> bytes:
level = [h(l) for l in leaves]
while len(level) > 1:
if len(level) % 2: level.append(level[-1]) # duplicate last
level = [h(level[i] + level[i+1]) for i in range(0, len(level), 2)]
return level[0]
def verify_inclusion(leaf: bytes, proof: list[tuple[str, bytes]],
root: bytes) -> bool:
node = h(leaf)
for side, sib in proof: # side: "L" | "R"
node = h(sib + node) if side == "L" else h(node + sib)
return node == root
4 · RFC 3161 による外部アンカリング(シェル)
署名済みバッチルートを公開タイムスタンプ局でアンカーすることは、INT-006の軽量側の要件を満たす。 リクエスト・レスポンス・TSA証明書は Evidence Pack に保持する。
# Anchor a signed Merkle root with an RFC 3161 time-stamping authority
openssl ts -query -data anchor_root.bin -sha256 -cert -out req.tsq
curl -s -H "Content-Type: application/timestamp-query" \
--data-binary @req.tsq https://tsa.example.org/ -o resp.tsr
openssl ts -reply -in resp.tsr -text # inspect the token
# Keep req.tsq + resp.tsr + the TSA certificate in the Evidence Pack
5 · 検証者が確認すること
- イベントハッシュの再計算 — 正規化JSONから再計算し照合する。
- チェーンの走査 — すべての
prev_hashが直前のイベントと一致し、説明のない断絶がない。 - 署名検証(Ed25519 / RFC 8032)— 登録済みオペレーター鍵に対して検証する。
- Merkle包含証明 — 各イベントがバッチのルートに含まれることを検証する。
- アンカー検証 — 署名済みルートに対する RFC 3161 トークン(または透明性ログ証明)を検証する。
- INT-008 バインディング照合 — AnchorRecord が宣言するイベント件数・先頭/末尾イベントID・ポリシー識別子が提示内容と一致する。不一致は省略/スプリットビューの証拠となる。
検証合格が意味するのは、記録が完全(アンカー粒度)で、無傷で、帰属可能である ことだけである。§1.6のとおり、基盤となる判断が正しかったか・公平だったか・安全だったかについては 何も述べない。