@kya-os/contracts 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ export declare const AgentContextSchema: z.ZodObject<{
9
9
  scopes: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
10
10
  session: z.ZodString;
11
11
  confidence: z.ZodLiteral<"verified">;
12
+ outcome: z.ZodOptional<z.ZodEnum<["allowed", "denied", "step_up_required", "needs_authorization"]>>;
12
13
  delegationRef: z.ZodOptional<z.ZodString>;
13
14
  registry: z.ZodString;
14
15
  verifiedAt: z.ZodNumber;
@@ -22,6 +23,7 @@ export declare const AgentContextSchema: z.ZodObject<{
22
23
  verifiedAt: number;
23
24
  subject?: string | undefined;
24
25
  delegationRef?: string | undefined;
26
+ outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
25
27
  }, {
26
28
  did: string;
27
29
  kid: string;
@@ -31,6 +33,7 @@ export declare const AgentContextSchema: z.ZodObject<{
31
33
  verifiedAt: number;
32
34
  subject?: string | undefined;
33
35
  delegationRef?: string | undefined;
36
+ outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
34
37
  scopes?: string[] | undefined;
35
38
  }>;
36
39
  export declare const VerifierResultSchema: z.ZodObject<{
@@ -43,6 +46,7 @@ export declare const VerifierResultSchema: z.ZodObject<{
43
46
  scopes: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
44
47
  session: z.ZodString;
45
48
  confidence: z.ZodLiteral<"verified">;
49
+ outcome: z.ZodOptional<z.ZodEnum<["allowed", "denied", "step_up_required", "needs_authorization"]>>;
46
50
  delegationRef: z.ZodOptional<z.ZodString>;
47
51
  registry: z.ZodString;
48
52
  verifiedAt: z.ZodNumber;
@@ -56,6 +60,7 @@ export declare const VerifierResultSchema: z.ZodObject<{
56
60
  verifiedAt: number;
57
61
  subject?: string | undefined;
58
62
  delegationRef?: string | undefined;
63
+ outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
59
64
  }, {
60
65
  did: string;
61
66
  kid: string;
@@ -65,6 +70,7 @@ export declare const VerifierResultSchema: z.ZodObject<{
65
70
  verifiedAt: number;
66
71
  subject?: string | undefined;
67
72
  delegationRef?: string | undefined;
73
+ outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
68
74
  scopes?: string[] | undefined;
69
75
  }>>;
70
76
  error: z.ZodOptional<z.ZodObject<{
@@ -85,6 +91,12 @@ export declare const VerifierResultSchema: z.ZodObject<{
85
91
  }>>;
86
92
  }, "strip", z.ZodTypeAny, {
87
93
  success: boolean;
94
+ error?: {
95
+ code: string;
96
+ message: string;
97
+ httpStatus: number;
98
+ details?: any;
99
+ } | undefined;
88
100
  headers?: Record<string, string> | undefined;
89
101
  agentContext?: {
90
102
  did: string;
@@ -96,15 +108,16 @@ export declare const VerifierResultSchema: z.ZodObject<{
96
108
  verifiedAt: number;
97
109
  subject?: string | undefined;
98
110
  delegationRef?: string | undefined;
111
+ outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
99
112
  } | undefined;
113
+ }, {
114
+ success: boolean;
100
115
  error?: {
101
116
  code: string;
102
117
  message: string;
103
118
  httpStatus: number;
104
119
  details?: any;
105
120
  } | undefined;
106
- }, {
107
- success: boolean;
108
121
  headers?: Record<string, string> | undefined;
109
122
  agentContext?: {
110
123
  did: string;
@@ -115,14 +128,9 @@ export declare const VerifierResultSchema: z.ZodObject<{
115
128
  verifiedAt: number;
116
129
  subject?: string | undefined;
117
130
  delegationRef?: string | undefined;
131
+ outcome?: "allowed" | "denied" | "step_up_required" | "needs_authorization" | undefined;
118
132
  scopes?: string[] | undefined;
119
133
  } | undefined;
120
- error?: {
121
- code: string;
122
- message: string;
123
- httpStatus: number;
124
- details?: any;
125
- } | undefined;
126
134
  }>;
127
135
  export declare const StructuredErrorSchema: z.ZodObject<{
128
136
  code: z.ZodString;
@@ -169,15 +177,16 @@ export type AgentContext = z.infer<typeof AgentContextSchema>;
169
177
  export type VerifierResult = z.infer<typeof VerifierResultSchema>;
170
178
  export type StructuredError = z.infer<typeof StructuredErrorSchema>;
171
179
  export declare const AGENT_HEADERS: {
172
- readonly DID: "KYA-Agent-DID";
173
- readonly KEY_ID: "KYA-Agent-KeyId";
174
- readonly SUBJECT: "KYA-Agent-Subject";
175
- readonly SCOPES: "KYA-Agent-Scopes";
176
- readonly SESSION: "KYA-Agent-Session";
177
- readonly CONFIDENCE: "KYA-Agent-Confidence";
178
- readonly DELEGATION_REF: "KYA-Delegation-Ref";
179
- readonly REGISTRY: "KYA-Agent-Registry";
180
- readonly VERIFIED_AT: "KYA-Verified-At";
180
+ readonly DID: "KYA-OS-Agent-DID";
181
+ readonly KEY_ID: "KYA-OS-Agent-KeyId";
182
+ readonly SUBJECT: "KYA-OS-Agent-Subject";
183
+ readonly SCOPES: "KYA-OS-Agent-Scopes";
184
+ readonly SESSION: "KYA-OS-Agent-Session";
185
+ readonly CONFIDENCE: "KYA-OS-Agent-Confidence";
186
+ readonly OUTCOME: "KYA-OS-Agent-Outcome";
187
+ readonly DELEGATION_REF: "KYA-OS-Delegation-Ref";
188
+ readonly REGISTRY: "KYA-OS-Agent-Registry";
189
+ readonly VERIFIED_AT: "KYA-OS-Verified-At";
181
190
  };
182
191
  export declare const VERIFIER_ERROR_CODES: {
183
192
  readonly PROOF_INVALID_TS: "XMCP_I_PROOF_INVALID_TS";
@@ -186,6 +195,7 @@ export declare const VERIFIER_ERROR_CODES: {
186
195
  readonly PROOF_SKEW_EXCEEDED: "XMCP_I_PROOF_SKEW_EXCEEDED";
187
196
  readonly SESSION_IDLE_EXPIRED: "XMCP_I_SESSION_IDLE_EXPIRED";
188
197
  readonly SERVER_TIME_INVALID: "XMCP_I_SERVER_TIME_INVALID";
198
+ readonly OUTCOME_NOT_ALLOWED: "XMCP_I_OUTCOME_NOT_ALLOWED";
189
199
  };
190
200
  export declare const ERROR_HTTP_STATUS: {
191
201
  readonly XMCP_I_EBADPROOF: 403;
@@ -202,4 +212,5 @@ export declare const ERROR_HTTP_STATUS: {
202
212
  readonly XMCP_I_PROOF_SKEW_EXCEEDED: 401;
203
213
  readonly XMCP_I_SESSION_IDLE_EXPIRED: 401;
204
214
  readonly XMCP_I_SERVER_TIME_INVALID: 500;
215
+ readonly XMCP_I_OUTCOME_NOT_ALLOWED: 403;
205
216
  };
package/dist/verifier.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ERROR_HTTP_STATUS = exports.VERIFIER_ERROR_CODES = exports.AGENT_HEADERS = exports.StructuredErrorSchema = exports.VerifierResultSchema = exports.AgentContextSchema = void 0;
4
4
  const zod_1 = require("zod");
5
+ const proof_js_1 = require("./proof.js");
5
6
  /**
6
7
  * Verifier middleware schemas and headers
7
8
  */
@@ -12,6 +13,13 @@ exports.AgentContextSchema = zod_1.z.object({
12
13
  scopes: zod_1.z.array(zod_1.z.string()).default([]),
13
14
  session: zod_1.z.string().min(1),
14
15
  confidence: zod_1.z.literal("verified"),
16
+ // Policy outcome the verified proof attests to (ratified DIF decision).
17
+ // `confidence: "verified"` means the proof is authentic; `outcome` is the
18
+ // separate authorization dimension. A PEP must gate on `outcome === "allowed"`
19
+ // — a verified `denied` / `step_up_required` / `needs_authorization` proof is
20
+ // authentic but does NOT authorize the call. Optional for backward
21
+ // compatibility; the verifier always populates it (legacy proofs → "allowed").
22
+ outcome: proof_js_1.ProofOutcomeSchema.optional(),
15
23
  delegationRef: zod_1.z.string().optional(),
16
24
  registry: zod_1.z.string().url(),
17
25
  verifiedAt: zod_1.z.number().int().positive(),
@@ -44,15 +52,16 @@ exports.StructuredErrorSchema = zod_1.z.object({
44
52
  });
45
53
  // Header constants (frozen names)
46
54
  exports.AGENT_HEADERS = {
47
- DID: "KYA-Agent-DID",
48
- KEY_ID: "KYA-Agent-KeyId",
49
- SUBJECT: "KYA-Agent-Subject",
50
- SCOPES: "KYA-Agent-Scopes",
51
- SESSION: "KYA-Agent-Session",
52
- CONFIDENCE: "KYA-Agent-Confidence",
53
- DELEGATION_REF: "KYA-Delegation-Ref",
54
- REGISTRY: "KYA-Agent-Registry",
55
- VERIFIED_AT: "KYA-Verified-At",
55
+ DID: "KYA-OS-Agent-DID",
56
+ KEY_ID: "KYA-OS-Agent-KeyId",
57
+ SUBJECT: "KYA-OS-Agent-Subject",
58
+ SCOPES: "KYA-OS-Agent-Scopes",
59
+ SESSION: "KYA-OS-Agent-Session",
60
+ CONFIDENCE: "KYA-OS-Agent-Confidence",
61
+ OUTCOME: "KYA-OS-Agent-Outcome",
62
+ DELEGATION_REF: "KYA-OS-Delegation-Ref",
63
+ REGISTRY: "KYA-OS-Agent-Registry",
64
+ VERIFIED_AT: "KYA-OS-Verified-At",
56
65
  };
57
66
  // Verifier-specific error codes
58
67
  exports.VERIFIER_ERROR_CODES = {
@@ -62,6 +71,7 @@ exports.VERIFIER_ERROR_CODES = {
62
71
  PROOF_SKEW_EXCEEDED: "XMCP_I_PROOF_SKEW_EXCEEDED",
63
72
  SESSION_IDLE_EXPIRED: "XMCP_I_SESSION_IDLE_EXPIRED",
64
73
  SERVER_TIME_INVALID: "XMCP_I_SERVER_TIME_INVALID",
74
+ OUTCOME_NOT_ALLOWED: "XMCP_I_OUTCOME_NOT_ALLOWED",
65
75
  };
66
76
  // HTTP status mappings
67
77
  exports.ERROR_HTTP_STATUS = {
@@ -80,4 +90,5 @@ exports.ERROR_HTTP_STATUS = {
80
90
  [exports.VERIFIER_ERROR_CODES.PROOF_SKEW_EXCEEDED]: 401,
81
91
  [exports.VERIFIER_ERROR_CODES.SESSION_IDLE_EXPIRED]: 401,
82
92
  [exports.VERIFIER_ERROR_CODES.SERVER_TIME_INVALID]: 500,
93
+ [exports.VERIFIER_ERROR_CODES.OUTCOME_NOT_ALLOWED]: 403,
83
94
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kya-os/contracts",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Shared contracts, types, and schemas for MCP-I framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -142,6 +142,7 @@
142
142
  },
143
143
  "files": [
144
144
  "dist",
145
+ "parity-vectors",
145
146
  "package.json",
146
147
  "README.md"
147
148
  ],
@@ -0,0 +1,265 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "name": "Delegation chain conformance vectors",
4
+ "description": "Cascading-revocation, chain-integrity, per-hop attenuation, and multi-hop delegation chains (E3.5 / issue #2904). `core` = full reference semantics (mcp-i-core cascading-revocation + delegation-graph, contracts areChildConstraintsValid). `edge` = reduced-profile kya-os-engine verdict: single-hop is evaluated; multi-hop fails closed to Block(PolicyDenied) unless a higher-priority reason (Revoked/Expired) fires first.",
5
+ "version": "1.0.0",
6
+ "vectors": [
7
+ {
8
+ "id": "cascade-revoke-ancestor-revokes-leaf",
9
+ "category": "cascading-revocation",
10
+ "profiles": ["core", "edge"],
11
+ "description": "Two-hop chain whose root delegation is revoked while the leaf's own credential is clean. Core: leaf invalid via ancestor cascade. Edge: the engine sees only the leaf's top-level credentialStatus (clean) and cannot observe the ancestor revocation, so it fails closed on the multi-hop chain (PolicyDenied) rather than over-permitting.",
12
+ "input": {
13
+ "chain": [
14
+ {
15
+ "id": "cr-root",
16
+ "parentId": null,
17
+ "issuerDid": "did:web:org.example",
18
+ "subjectDid": "did:web:agent.example",
19
+ "grantedScopes": ["read:*"],
20
+ "credentialStatusId": "https://status.example/revocation/v1#5"
21
+ },
22
+ {
23
+ "id": "cr-leaf",
24
+ "parentId": "cr-root",
25
+ "issuerDid": "did:web:agent.example",
26
+ "subjectDid": "did:key:zSubLeaf",
27
+ "grantedScopes": ["read:email"],
28
+ "credentialStatusId": "https://status.example/revocation/v1#9"
29
+ }
30
+ ],
31
+ "requestedScope": "read:email",
32
+ "revokedStatusIds": ["https://status.example/revocation/v1#5"],
33
+ "currentTime": 1735689600
34
+ },
35
+ "expected": {
36
+ "core": {
37
+ "valid": false,
38
+ "failureReason": "cascaded-revocation",
39
+ "revokedAncestor": "cr-root"
40
+ },
41
+ "edge": {
42
+ "mode": "fail-closed",
43
+ "decision": {
44
+ "kind": "Block",
45
+ "reason": {
46
+ "kind": "PolicyDenied",
47
+ "detail": "multi-hop delegation chain (len=2) not evaluated by reduced edge profile; Layer-2 policy authoritative"
48
+ }
49
+ }
50
+ }
51
+ },
52
+ "note": "The leaf's own credentialStatus (#9) is NOT revoked, so the engine's Stage 3 does not fire Block(Revoked); the multi-hop guard yields PolicyDenied. If the leaf's own status WERE revoked, Stage 3's Revoked (priority 0) would outrank PolicyDenied — covered by the cross-runtime matrix, not here."
53
+ },
54
+ {
55
+ "id": "chain-integrity-broken-issuer-linkage",
56
+ "category": "chain-integrity",
57
+ "profiles": ["core", "edge"],
58
+ "description": "Two-hop chain where the leaf's issuer is NOT the root's subject (forged intermediate). Core: invalid-chain via delegation-graph linkage check. Edge: fails closed on the multi-hop chain.",
59
+ "input": {
60
+ "chain": [
61
+ {
62
+ "id": "ci-root",
63
+ "parentId": null,
64
+ "issuerDid": "did:web:org.example",
65
+ "subjectDid": "did:web:agent.example",
66
+ "grantedScopes": ["read:*"]
67
+ },
68
+ {
69
+ "id": "ci-leaf",
70
+ "parentId": "ci-root",
71
+ "issuerDid": "did:web:evil.example",
72
+ "subjectDid": "did:key:zSubLeaf",
73
+ "grantedScopes": ["read:email"]
74
+ }
75
+ ],
76
+ "requestedScope": "read:email",
77
+ "currentTime": 1735689600
78
+ },
79
+ "expected": {
80
+ "core": {
81
+ "valid": false,
82
+ "failureReason": "invalid-chain"
83
+ },
84
+ "edge": {
85
+ "mode": "fail-closed",
86
+ "decision": {
87
+ "kind": "Block",
88
+ "reason": {
89
+ "kind": "PolicyDenied",
90
+ "detail": "multi-hop delegation chain (len=2) not evaluated by reduced edge profile; Layer-2 policy authoritative"
91
+ }
92
+ }
93
+ }
94
+ },
95
+ "note": "delegation-graph.validateChain requires child.issuerDid === parent.subjectDid (delegation-graph.ts:243). did:web:evil.example breaks the linkage. The flat engine carries no per-hop issuer/subject, so it cannot detect this — fail-closed is the safe reduced-profile behavior."
96
+ },
97
+ {
98
+ "id": "attenuation-child-exceeds-parent-scope",
99
+ "category": "per-hop-attenuation",
100
+ "profiles": ["core", "edge"],
101
+ "description": "Two-hop chain where the child grants MORE than the parent (parent read:* via prefix, child write:billing). Core: attenuation-violation via areChildConstraintsValid. Edge: fails closed. This is the canonical over-permit case the reduced profile closes.",
102
+ "input": {
103
+ "chain": [
104
+ {
105
+ "id": "at-root",
106
+ "parentId": null,
107
+ "issuerDid": "did:web:org.example",
108
+ "subjectDid": "did:web:agent.example",
109
+ "grantedScopes": ["read:*"],
110
+ "constraints": {
111
+ "crisp": {
112
+ "scopes": [{ "resource": "read:", "matcher": "prefix" }]
113
+ }
114
+ }
115
+ },
116
+ {
117
+ "id": "at-leaf",
118
+ "parentId": "at-root",
119
+ "issuerDid": "did:web:agent.example",
120
+ "subjectDid": "did:key:zSubLeaf",
121
+ "grantedScopes": ["write:billing"],
122
+ "constraints": {
123
+ "crisp": {
124
+ "scopes": [{ "resource": "write:billing", "matcher": "exact" }]
125
+ }
126
+ }
127
+ }
128
+ ],
129
+ "requestedScope": "write:billing",
130
+ "currentTime": 1735689600
131
+ },
132
+ "expected": {
133
+ "core": {
134
+ "valid": false,
135
+ "failureReason": "attenuation-violation"
136
+ },
137
+ "edge": {
138
+ "mode": "fail-closed",
139
+ "decision": {
140
+ "kind": "Block",
141
+ "reason": {
142
+ "kind": "PolicyDenied",
143
+ "detail": "multi-hop delegation chain (len=2) not evaluated by reduced edge profile; Layer-2 policy authoritative"
144
+ }
145
+ }
146
+ }
147
+ },
148
+ "note": "Today the flat engine would flatten grants to [read:*, write:billing] and scope_satisfies('write:billing', ...) === true → silent Permit. areChildConstraintsValid rejects the widening (write:billing does not start with read:). Fail-closed converts the silent over-permit into Block(PolicyDenied)."
149
+ },
150
+ {
151
+ "id": "multihop-valid-chain-still-fail-closed",
152
+ "category": "multi-hop-valid",
153
+ "profiles": ["core", "edge"],
154
+ "description": "A WELL-FORMED two-hop chain: valid linkage, no revocation, child scopes within parent, request within leaf grant. Core: valid. Edge: STILL fails closed — the reduced profile does not certify multi-hop even when the chain is valid; the over-permit risk is structural, not data-dependent.",
155
+ "input": {
156
+ "chain": [
157
+ {
158
+ "id": "hp-root",
159
+ "parentId": null,
160
+ "issuerDid": "did:web:org.example",
161
+ "subjectDid": "did:web:agent.example",
162
+ "grantedScopes": ["read:email"],
163
+ "credentialStatusId": "https://status.example/revocation/v1#20",
164
+ "constraints": {
165
+ "crisp": {
166
+ "scopes": [{ "resource": "read:email", "matcher": "exact" }]
167
+ }
168
+ }
169
+ },
170
+ {
171
+ "id": "hp-leaf",
172
+ "parentId": "hp-root",
173
+ "issuerDid": "did:web:agent.example",
174
+ "subjectDid": "did:key:zSubLeaf",
175
+ "grantedScopes": ["read:email"],
176
+ "credentialStatusId": "https://status.example/revocation/v1#21",
177
+ "constraints": {
178
+ "crisp": {
179
+ "scopes": [{ "resource": "read:email", "matcher": "exact" }]
180
+ }
181
+ }
182
+ }
183
+ ],
184
+ "requestedScope": "read:email",
185
+ "revokedStatusIds": [],
186
+ "currentTime": 1735689600
187
+ },
188
+ "expected": {
189
+ "core": {
190
+ "valid": true
191
+ },
192
+ "edge": {
193
+ "mode": "fail-closed",
194
+ "decision": {
195
+ "kind": "Block",
196
+ "reason": {
197
+ "kind": "PolicyDenied",
198
+ "detail": "multi-hop delegation chain (len=2) not evaluated by reduced edge profile; Layer-2 policy authoritative"
199
+ }
200
+ }
201
+ }
202
+ },
203
+ "note": "Deliberate negative-of-convenience: proves the edge profile fails closed even on a VALID multi-hop chain. This is the honest cost of the reduced profile — Layer-2 tenant policy must opt these back in. Prevents a future maintainer from 'optimizing' the guard to permit valid-looking chains."
204
+ },
205
+ {
206
+ "id": "singlehop-scope-permit",
207
+ "category": "scope-match",
208
+ "profiles": ["edge"],
209
+ "description": "Single-hop delegation whose granted scope covers the requested scope. Edge: evaluated → Permit (regression guard that the multi-hop guard does NOT change the len<=1 path).",
210
+ "input": {
211
+ "chain": [
212
+ {
213
+ "id": "sh-permit",
214
+ "parentId": null,
215
+ "issuerDid": "did:web:org.example",
216
+ "subjectDid": "did:web:agent.example",
217
+ "grantedScopes": ["read:email"]
218
+ }
219
+ ],
220
+ "requestedScope": "read:email",
221
+ "currentTime": 1735689600
222
+ },
223
+ "expected": {
224
+ "edge": {
225
+ "mode": "evaluated",
226
+ "decision": { "kind": "Permit" }
227
+ }
228
+ },
229
+ "note": "Single-hop is within the engine's competence: it flattens the one step's grants and matches requestedScope. No core counterpart — for single-hop scope the engine is the reference."
230
+ },
231
+ {
232
+ "id": "singlehop-scope-out-of-scope",
233
+ "category": "scope-match",
234
+ "profiles": ["edge"],
235
+ "description": "Single-hop delegation whose granted scope does NOT cover the requested scope. Edge: evaluated → Block(OutOfScope). Proves the guard leaves the genuine single-hop scope rejection intact.",
236
+ "input": {
237
+ "chain": [
238
+ {
239
+ "id": "sh-oos",
240
+ "parentId": null,
241
+ "issuerDid": "did:web:org.example",
242
+ "subjectDid": "did:web:agent.example",
243
+ "grantedScopes": ["read:email"]
244
+ }
245
+ ],
246
+ "requestedScope": "write:billing",
247
+ "currentTime": 1735689600
248
+ },
249
+ "expected": {
250
+ "edge": {
251
+ "mode": "evaluated",
252
+ "decision": {
253
+ "kind": "Block",
254
+ "reason": {
255
+ "kind": "OutOfScope",
256
+ "requested": "write:billing",
257
+ "granted": ["read:email"]
258
+ }
259
+ }
260
+ }
261
+ },
262
+ "note": "Single-hop OutOfScope stays a genuine evaluated rejection (not fail-closed). granted is the flattened single-step grant set."
263
+ }
264
+ ]
265
+ }
@@ -0,0 +1,134 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "name": "did:key resolution test vectors",
4
+ "description": "Test vectors for did:key resolution parity between TypeScript and Rust",
5
+ "version": "1.0.0",
6
+ "vectors": [
7
+ {
8
+ "id": "valid-ed25519-1",
9
+ "description": "Valid Ed25519 did:key",
10
+ "input": {
11
+ "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
12
+ },
13
+ "expected": {
14
+ "success": true,
15
+ "keyType": "Ed25519",
16
+ "publicKeyHex": "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
17
+ "keyId": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
18
+ }
19
+ },
20
+ {
21
+ "id": "valid-ed25519-2",
22
+ "description": "Another valid Ed25519 did:key",
23
+ "input": {
24
+ "did": "did:key:z6MkfrNzYH9ygZbUjWKFW3BrN5SvXqWMQGQwYVaR8GGJqWLb"
25
+ },
26
+ "expected": {
27
+ "success": true,
28
+ "keyType": "Ed25519"
29
+ }
30
+ },
31
+ {
32
+ "id": "invalid-empty",
33
+ "description": "Empty DID string",
34
+ "input": {
35
+ "did": ""
36
+ },
37
+ "expected": {
38
+ "success": false,
39
+ "errorType": "InvalidFormat"
40
+ }
41
+ },
42
+ {
43
+ "id": "invalid-not-did-key",
44
+ "description": "Wrong DID method (did:web instead of did:key)",
45
+ "input": {
46
+ "did": "did:web:example.com"
47
+ },
48
+ "expected": {
49
+ "success": false,
50
+ "errorType": "InvalidPrefix"
51
+ }
52
+ },
53
+ {
54
+ "id": "invalid-multibase-prefix",
55
+ "description": "Invalid multibase prefix (not z)",
56
+ "input": {
57
+ "did": "did:key:f6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
58
+ },
59
+ "expected": {
60
+ "success": false,
61
+ "errorType": "InvalidMultibase"
62
+ }
63
+ },
64
+ {
65
+ "id": "invalid-base58",
66
+ "description": "Invalid base58 encoding (contains 0, O, I, l)",
67
+ "input": {
68
+ "did": "did:key:z6Mk0OIl"
69
+ },
70
+ "expected": {
71
+ "success": false,
72
+ "errorType": "InvalidBase58"
73
+ }
74
+ },
75
+ {
76
+ "id": "unsupported-curve-p256",
77
+ "description": "Unsupported curve (P-256)",
78
+ "input": {
79
+ "did": "did:key:zDnaeucDGfNLZfcPeDpQWAcfJMCvzNjrB5F9Xut7VH8fFYnDW"
80
+ },
81
+ "expected": {
82
+ "success": false,
83
+ "errorType": "UnsupportedKeyType"
84
+ }
85
+ },
86
+ {
87
+ "id": "unsupported-curve-secp256k1",
88
+ "description": "Unsupported curve (secp256k1)",
89
+ "input": {
90
+ "did": "did:key:zQ3shNFbC9Wk5yXnNMEsNz1hL5NPcUHbBYC8TmUHxAHhVWFqe"
91
+ },
92
+ "expected": {
93
+ "success": false,
94
+ "errorType": "UnsupportedKeyType"
95
+ }
96
+ },
97
+ {
98
+ "id": "invalid-key-length",
99
+ "description": "Invalid key length (too short)",
100
+ "input": {
101
+ "did": "did:key:z6MkTest"
102
+ },
103
+ "expected": {
104
+ "success": false,
105
+ "errorType": "InvalidKeyLength"
106
+ }
107
+ },
108
+ {
109
+ "id": "valid-key-id-validation",
110
+ "description": "Validate key ID format",
111
+ "input": {
112
+ "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
113
+ "keyId": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
114
+ },
115
+ "expected": {
116
+ "success": true,
117
+ "keyIdValid": true
118
+ }
119
+ },
120
+ {
121
+ "id": "invalid-key-id-mismatch",
122
+ "description": "Key ID does not match DID",
123
+ "input": {
124
+ "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
125
+ "keyId": "did:key:z6MkfrNzYH9ygZbUjWKFW3BrN5SvXqWMQGQwYVaR8GGJqWLb#z6MkfrNzYH9ygZbUjWKFW3BrN5SvXqWMQGQwYVaR8GGJqWLb"
126
+ },
127
+ "expected": {
128
+ "success": false,
129
+ "keyIdValid": false,
130
+ "errorType": "KeyIdMismatch"
131
+ }
132
+ }
133
+ ]
134
+ }