W3C Verifiable Credentials Data Model
このドキュメントでは、VC のデータ構造 を「最小限の VC」から始めて段階的に理解していきます。
まず結論:VC は「署名付き JSON」
VC の本質はシンプルです。
VC = 主張(クレーム)+ 発行者情報 + デジタル署名
例: 「山田太郎は21歳以上である」という主張
+ 「公安委員会が発行した」という情報
+ 公安委員会のデジタル署名
これを JSON で表現したものが VC Data Model です。
最小限の VC から理解する
Step 1: 最もシンプルな VC
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential"],
"issuer": "did:example:issuer",
"credentialSubject": {
"id": "did:example:holder",
"ageOver21": true
}
}
たった4つのフィールドで VC になります。
┌─────────────────────────────────────────────────────────────┐
│ │
│ @context ─────► 「これは VC です」という宣言 │
│ │
│ type ─────────► 「検証可能なクレデンシャル」という種類 │
│ │
│ issuer ───────► 「did:example:issuer が発行した」 │
│ │
│ credentialSubject │
│ └── id ─────► 「did:example:holder について」 │
│ └── ageOver21 ► 「21歳以上である」という主張 │
│ │
└─────────────────────────────────────────────────────────────┘
Step 2: 署名を追加
署名がないと「検証可能」になりません。
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential"],
"issuer": "did:example:issuer",
"credentialSubject": {
"id": "did:example:holder",
"ageOver21": true
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:example:issuer#key-1",
"proofValue": "z3FXQjecWufY46..."
}
}
proof が追加されたことで:
検証者 ────► issuer の公開鍵を取得
────► proofValue を検証
────► 「本当に issuer が発行したか」を確認できる!
Step 3: 有効期限を追加
いつからいつまで有効かを指定します。
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential"],
"issuer": "did:example:issuer",
"validFrom": "2024-01-01T00:00:00Z",
"validUntil": "2029-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:holder",
"ageOver21": true
},
"proof": { ... }
}
有効期間のチェック:
validFrom ──────────────────────── validUntil
│ │
│ ← この期間内なら有効 → │
│ │
2024/1/1 2029/1/1
検証時:
現在時刻が validFrom より後 かつ validUntil より前
→ 有効!
Step 4: 失効確認を追加
「途中で無効にしたい」場合に必要です。
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential"],
"issuer": "did:example:issuer",
"validFrom": "2024-01-01T00:00:00Z",
"validUntil": "2029-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:holder",
"ageOver21": true
},
"credentialStatus": {
"type": "BitstringStatusListEntry",
"statusListCredential": "https://issuer.example/status/1",
"statusListIndex": "12345"
},
"proof": { ... }
}
なぜ失効確認が必要?
例: スマホを紛失した場合
1. 保持者が発行者に連絡
2. 発行者が status list を更新
status[12345] = 1 (失効)
3. 検証者がチェック
→ 「失効している」と判定
各フィールドの詳細
@context:「これは何か」を定義
なぜ必要?
JSON だけでは ageOver21 が何を意味するかわかりません。
// これだけ見ても意味不明
{ "ageOver21": true }
// @context があると意味が定義される
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"ageOver21": true
}
// → 「W3C の VC 仕様における ageOver21」という意味
ルール:
- 最初は必ず
https://www.w3.org/ns/credentials/v2 - 追加の語彙を使う場合は配列で追加
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://example.gov/credentials/driver-license/v1"
]
}
type:クレデンシャルの種類
なぜ必要?
「これはどんな種類のクレデンシャルか」を示します。
{
"type": ["VerifiableCredential", "UniversityDegreeCredential"]
}
type の意味:
VerifiableCredential ───► 必須。「これは VC です」
UniversityDegreeCredential ► 追加。「大学の学位証明です」
検証者は type を見て:
「この VC は大学の学位証明だな」
「必要なフィールドが含まれているはず」
と判断できる
issuer:誰が発行したか
文字列形式:
{
"issuer": "did:example:university"
}
オブジェクト形式(追加情報付き):
{
"issuer": {
"id": "did:example:university",
"name": "東京大学"
}
}
issuer の検証:
1. issuer の DID を解決
2. DID Document から公開鍵を取得
3. proof の署名を検証
4. 「本当にこの issuer が署名したか」を確認
信頼の問題:
issuer が「東京大学」を名乗っているからといって
本当に東京大学とは限らない!
→ 検証者は「信頼できる issuer のリスト」を持つ必要がある
→ または「信頼できるルート」からの証明書チェーン
credentialSubject:誰について、何を主張するか
シンプルな例:
{
"credentialSubject": {
"id": "did:example:holder",
"ageOver21": true
}
}