@adastracomputing/ink 0.1.0-alpha.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.
- package/CHANGELOG.md +63 -0
- package/CODE_OF_CONDUCT.md +42 -0
- package/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +21 -0
- package/README.md +133 -0
- package/SECURITY.md +57 -0
- package/docs/key-rotation-rule.md +108 -0
- package/docs/logo.svg +8 -0
- package/docs/maturity.md +81 -0
- package/docs/threat-model.md +150 -0
- package/package.json +72 -0
- package/specs/ink-agent-containment-and-governance-extension-spec.md +508 -0
- package/specs/ink-auditability.md +652 -0
- package/specs/ink-authorization-chain.md +242 -0
- package/specs/ink-compatibility-policy.md +263 -0
- package/specs/ink-compliance-checklist.md +309 -0
- package/specs/ink-containment-phase1-implementation-spec.md +593 -0
- package/specs/ink-introduction-receipts-extension.md +501 -0
- package/specs/ink-key-rotation-spec.md +535 -0
- package/src/crypto/ink.ts +902 -0
- package/src/crypto/keys.ts +211 -0
- package/src/crypto/multi-key-verify.ts +170 -0
- package/src/crypto/sign.ts +155 -0
- package/src/crypto/verify.ts +1 -0
- package/src/discovery/agent-card.ts +508 -0
- package/src/index.ts +59 -0
- package/src/ink/checkpoint.ts +75 -0
- package/src/ink/discovery-gating.ts +147 -0
- package/src/ink/handshake-budget.ts +413 -0
- package/src/ink/receipts.ts +114 -0
- package/src/ink/transport-auth.ts +96 -0
- package/src/middleware/ink-auth.ts +263 -0
- package/src/models/agent-card.ts +63 -0
- package/src/models/ink-audit.ts +205 -0
- package/src/models/ink-handshake.ts +123 -0
- package/src/models/intent.ts +201 -0
- package/src/models/key-entry.ts +52 -0
- package/src/models/profile.ts +31 -0
- package/test-vectors/README.md +129 -0
- package/test-vectors/encryption.json +90 -0
- package/test-vectors/handshake.json +482 -0
- package/test-vectors/jcs.json +30 -0
- package/test-vectors/key-rotation.json +101 -0
- package/test-vectors/keys.json +32 -0
- package/test-vectors/receipts-and-audit.json +142 -0
- package/test-vectors/replay.json +88 -0
- package/test-vectors/signing.json +61 -0
- package/test-vectors/witness.json +394 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
# INK Key Rotation Specification v0.1
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Draft
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
This specification defines how INK agents rotate signing and encryption keys without breaking:
|
|
9
|
+
- active message exchange
|
|
10
|
+
- historical verification
|
|
11
|
+
- witness verification
|
|
12
|
+
- counterparty discovery
|
|
13
|
+
|
|
14
|
+
Core principle:
|
|
15
|
+
|
|
16
|
+
**An INK agent's identity must remain stable across key changes, while its active and historical keys remain verifiable.**
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Problem
|
|
21
|
+
|
|
22
|
+
Today Tulpa implementations derive `agentId` from the signing public key.
|
|
23
|
+
|
|
24
|
+
That creates a protocol problem:
|
|
25
|
+
- rotating the signing key changes the apparent agent identity
|
|
26
|
+
- counterparties cannot safely distinguish key rotation from impersonation
|
|
27
|
+
- old receipts, audit events, and witness records still need verification
|
|
28
|
+
|
|
29
|
+
Therefore key rotation MUST be handled as a protocol concern, not a local storage concern.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. Goals
|
|
34
|
+
|
|
35
|
+
INK key rotation SHALL:
|
|
36
|
+
- preserve a stable logical agent identity
|
|
37
|
+
- allow new transport/auth signatures to verify under a new key
|
|
38
|
+
- preserve verification of historical artifacts signed by prior keys
|
|
39
|
+
- let counterparties discover key changes safely
|
|
40
|
+
- support overlap, retirement, and emergency revocation
|
|
41
|
+
|
|
42
|
+
INK key rotation SHALL NOT:
|
|
43
|
+
- require breaking message history
|
|
44
|
+
- require rewriting old receipts or audit events
|
|
45
|
+
- rely on out-of-band manual key distribution
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. Non-Goals
|
|
50
|
+
|
|
51
|
+
This spec does not define:
|
|
52
|
+
- human DID key rotation for ATP itself
|
|
53
|
+
- extension delegation token rotation
|
|
54
|
+
- witness service key rotation beyond discovery advertisement
|
|
55
|
+
|
|
56
|
+
Those may reuse the same patterns later, but are not required here.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 4. Identity Model
|
|
61
|
+
|
|
62
|
+
## 4.1 Stable Agent Identity
|
|
63
|
+
|
|
64
|
+
INK v1 SHALL treat `agentId` as a stable logical identifier, not as a direct encoding of the current signing key.
|
|
65
|
+
|
|
66
|
+
`agentId` MUST remain stable across key rotation.
|
|
67
|
+
|
|
68
|
+
## 4.2 Key Material
|
|
69
|
+
|
|
70
|
+
Each agent SHALL advertise one or more keys by role:
|
|
71
|
+
- signing keys
|
|
72
|
+
- encryption keys
|
|
73
|
+
|
|
74
|
+
Each key SHALL have:
|
|
75
|
+
- a stable `keyId`
|
|
76
|
+
- an algorithm
|
|
77
|
+
- a public key
|
|
78
|
+
- a lifecycle status
|
|
79
|
+
- validity timestamps
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 5. Agent Card Additions
|
|
84
|
+
|
|
85
|
+
## 5.1 Key Set Advertisement
|
|
86
|
+
|
|
87
|
+
The Agent Card SHALL advertise key sets explicitly.
|
|
88
|
+
|
|
89
|
+
Recommended shape:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"agentId": "did:plc:alice#agent/tulpa-main",
|
|
94
|
+
"protocol": "ink/0.1",
|
|
95
|
+
"keys": {
|
|
96
|
+
"signing": [
|
|
97
|
+
{
|
|
98
|
+
"keyId": "sig-2026-03",
|
|
99
|
+
"algorithm": "Ed25519",
|
|
100
|
+
"publicKeyMultibase": "z...",
|
|
101
|
+
"status": "active",
|
|
102
|
+
"validFrom": "2026-03-25T00:00:00Z"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"keyId": "sig-2025-11",
|
|
106
|
+
"algorithm": "Ed25519",
|
|
107
|
+
"publicKeyMultibase": "z...",
|
|
108
|
+
"status": "retired",
|
|
109
|
+
"validFrom": "2025-11-01T00:00:00Z",
|
|
110
|
+
"validUntil": "2026-04-01T00:00:00Z"
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"encryption": [
|
|
114
|
+
{
|
|
115
|
+
"keyId": "enc-2026-03",
|
|
116
|
+
"algorithm": "X25519",
|
|
117
|
+
"publicKeyMultibase": "z...",
|
|
118
|
+
"status": "active",
|
|
119
|
+
"validFrom": "2026-03-25T00:00:00Z"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"currentSigningKeyId": "sig-2026-03",
|
|
124
|
+
"currentEncryptionKeyId": "enc-2026-03",
|
|
125
|
+
"keySetVersion": 7,
|
|
126
|
+
"updatedAt": "2026-03-25T00:00:00Z"
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 5.2 Required Fields
|
|
131
|
+
|
|
132
|
+
Each key entry MUST include:
|
|
133
|
+
- `keyId`
|
|
134
|
+
- `algorithm`
|
|
135
|
+
- `publicKeyMultibase`
|
|
136
|
+
- `status`
|
|
137
|
+
- `validFrom`
|
|
138
|
+
|
|
139
|
+
Optional but recommended:
|
|
140
|
+
- `validUntil`
|
|
141
|
+
- `revokedAt`
|
|
142
|
+
- `revokeReason`
|
|
143
|
+
|
|
144
|
+
## 5.3 Status Values
|
|
145
|
+
|
|
146
|
+
Allowed statuses:
|
|
147
|
+
- `active`
|
|
148
|
+
- `retired`
|
|
149
|
+
- `revoked`
|
|
150
|
+
|
|
151
|
+
Meaning:
|
|
152
|
+
- `active`: valid for new outbound messages and inbound verification
|
|
153
|
+
- `retired`: not used for new outbound messages, but still valid for historical verification
|
|
154
|
+
- `revoked`: no longer trusted for new signatures after `revokedAt`
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 6. Signing Verification Rules
|
|
159
|
+
|
|
160
|
+
## 6.1 Current Messages
|
|
161
|
+
|
|
162
|
+
For current inbound messages, receivers MUST:
|
|
163
|
+
- resolve the sender's Agent Card
|
|
164
|
+
- attempt verification against active signing keys first
|
|
165
|
+
|
|
166
|
+
## 6.2 Historical Verification
|
|
167
|
+
|
|
168
|
+
For receipts, audit events, witness submissions, and previously stored messages, receivers MUST:
|
|
169
|
+
- permit verification against retired keys if the artifact timestamp falls within that key's validity window
|
|
170
|
+
|
|
171
|
+
## 6.3 Revoked Keys
|
|
172
|
+
|
|
173
|
+
Receivers MUST NOT verify signatures with a revoked key, even for artifacts whose timestamp predates `revokedAt`. Revocation is a trust statement: the key is compromised or must not be trusted, and pre-revocation artifacts cannot be distinguished from forgeries made after compromise.
|
|
174
|
+
|
|
175
|
+
This is the normative rule, see [`docs/key-rotation-rule.md`](../docs/key-rotation-rule.md). Retired is the correct status for keys that should remain verifiable for historical traffic.
|
|
176
|
+
|
|
177
|
+
## 6.4 Verification Order
|
|
178
|
+
|
|
179
|
+
Recommended verification order:
|
|
180
|
+
1. current active key by `currentSigningKeyId`
|
|
181
|
+
2. other active signing keys
|
|
182
|
+
3. retired signing keys
|
|
183
|
+
4. reject if no valid candidate verifies
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 7. Encryption Verification Rules
|
|
188
|
+
|
|
189
|
+
## 7.1 New Messages
|
|
190
|
+
|
|
191
|
+
Senders MUST encrypt to the recipient's current active encryption key.
|
|
192
|
+
|
|
193
|
+
## 7.2 Overlap Window
|
|
194
|
+
|
|
195
|
+
During rotation overlap, receivers SHOULD support decryption with:
|
|
196
|
+
- current active encryption key
|
|
197
|
+
- immediately previous retired encryption key
|
|
198
|
+
|
|
199
|
+
This allows delivery continuity during cache lag.
|
|
200
|
+
|
|
201
|
+
## 7.3 Retirement
|
|
202
|
+
|
|
203
|
+
An encryption key SHOULD NOT move to `revoked` until counterparties have had a documented overlap period to refresh the Agent Card.
|
|
204
|
+
|
|
205
|
+
Recommended minimum overlap:
|
|
206
|
+
- 7 days for planned rotation
|
|
207
|
+
|
|
208
|
+
Emergency revocation MAY be immediate.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 8. Rotation Flow
|
|
213
|
+
|
|
214
|
+
## 8.1 Planned Rotation
|
|
215
|
+
|
|
216
|
+
Recommended planned rotation flow:
|
|
217
|
+
|
|
218
|
+
1. Generate new keypair(s)
|
|
219
|
+
2. Publish updated Agent Card with:
|
|
220
|
+
- new key(s) marked `active`
|
|
221
|
+
- previous current key(s) marked `retired`
|
|
222
|
+
- incremented `keySetVersion`
|
|
223
|
+
3. Start signing new outbound messages with the new signing key
|
|
224
|
+
4. Start encrypting to the new encryption key
|
|
225
|
+
5. Accept verification/decryption with prior keys during overlap
|
|
226
|
+
6. After overlap, leave prior signing keys `retired` for historical verification
|
|
227
|
+
7. Revoke old encryption key if necessary
|
|
228
|
+
|
|
229
|
+
## 8.2 Emergency Rotation
|
|
230
|
+
|
|
231
|
+
For suspected compromise:
|
|
232
|
+
|
|
233
|
+
1. Publish updated Agent Card immediately
|
|
234
|
+
2. Mark compromised key `revoked`
|
|
235
|
+
3. Increment `keySetVersion`
|
|
236
|
+
4. Begin signing with new key immediately
|
|
237
|
+
5. Counterparties MUST refresh on verification miss or newer card version detection
|
|
238
|
+
|
|
239
|
+
Emergency revocation MAY break some in-flight encrypted delivery and this is acceptable.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 9. Discovery and Cache Invalidation
|
|
244
|
+
|
|
245
|
+
## 9.1 Canonical Discovery Surface
|
|
246
|
+
|
|
247
|
+
The Agent Card SHALL be the canonical discovery surface for current and historical INK keys.
|
|
248
|
+
|
|
249
|
+
If ATP-linked identity records or DID-linked materials are also used, they MUST be consistent with the Agent Card.
|
|
250
|
+
|
|
251
|
+
## 9.2 Cache Behavior
|
|
252
|
+
|
|
253
|
+
Implementations SHOULD cache discovered key sets, but MUST refresh when:
|
|
254
|
+
- signature verification fails for all cached active keys
|
|
255
|
+
- a message references an unknown `keyId`
|
|
256
|
+
- a newer `keySetVersion` is observed
|
|
257
|
+
- encryption to the current key fails due to key mismatch
|
|
258
|
+
|
|
259
|
+
## 9.3 Refresh Policy
|
|
260
|
+
|
|
261
|
+
Recommended cache TTL:
|
|
262
|
+
- 1 hour default
|
|
263
|
+
|
|
264
|
+
Recommended forced refresh triggers:
|
|
265
|
+
- verification miss
|
|
266
|
+
- explicit rotation signal
|
|
267
|
+
- card version monotonic increase
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 10. Optional Rotation Signal
|
|
272
|
+
|
|
273
|
+
INK MAY define an advisory message type:
|
|
274
|
+
- `network.tulpa.key_rotation`
|
|
275
|
+
|
|
276
|
+
Purpose:
|
|
277
|
+
- accelerate counterparty refresh
|
|
278
|
+
- reduce verification misses after planned rotation
|
|
279
|
+
|
|
280
|
+
This message MUST NOT be the sole source of truth.
|
|
281
|
+
|
|
282
|
+
The Agent Card remains canonical.
|
|
283
|
+
|
|
284
|
+
Recommended fields:
|
|
285
|
+
- `from`
|
|
286
|
+
- `to`
|
|
287
|
+
- `newKeySetVersion`
|
|
288
|
+
- `rotatedSigningKeyIds`
|
|
289
|
+
- `rotatedEncryptionKeyIds`
|
|
290
|
+
- `timestamp`
|
|
291
|
+
- `nonce`
|
|
292
|
+
|
|
293
|
+
Receivers SHOULD treat it as a hint to refresh discovery state.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## 11. Historical Verification
|
|
298
|
+
|
|
299
|
+
## 11.1 Requirement
|
|
300
|
+
|
|
301
|
+
INK implementations MUST preserve the ability to verify:
|
|
302
|
+
- stored messages
|
|
303
|
+
- receipts
|
|
304
|
+
- bilateral audit events
|
|
305
|
+
- witness submissions
|
|
306
|
+
- witness inclusion references
|
|
307
|
+
|
|
308
|
+
## 11.2 Historical Key Retention
|
|
309
|
+
|
|
310
|
+
Historical keys used for verification SHOULD remain available for at least:
|
|
311
|
+
- 90 days minimum
|
|
312
|
+
|
|
313
|
+
Recommended:
|
|
314
|
+
- retain indefinitely while marking status appropriately
|
|
315
|
+
|
|
316
|
+
If a system cannot retain historical keys indefinitely in the live Agent Card, it MUST provide a documented verified history surface.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 12. Witness Interaction
|
|
321
|
+
|
|
322
|
+
## 12.1 Submit Verification
|
|
323
|
+
|
|
324
|
+
Witness services MUST be able to verify audit submissions against:
|
|
325
|
+
- current active keys
|
|
326
|
+
- retired keys when validating older events or delayed submissions
|
|
327
|
+
|
|
328
|
+
## 12.2 Query Verification
|
|
329
|
+
|
|
330
|
+
Signed witness query verification MUST use the same rotation-aware signing-key lookup rules as other INK transport verification.
|
|
331
|
+
|
|
332
|
+
## 12.3 Retention
|
|
333
|
+
|
|
334
|
+
Witness implementations SHOULD cache or resolve historical keys in a way that preserves later verification of valid older events.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 13. Key IDs
|
|
339
|
+
|
|
340
|
+
## 13.1 Requirement
|
|
341
|
+
|
|
342
|
+
New INK signed messages SHOULD include the signing `keyId`.
|
|
343
|
+
|
|
344
|
+
This avoids trial-verifying across many candidate keys.
|
|
345
|
+
|
|
346
|
+
Recommended location:
|
|
347
|
+
- transport metadata or signed body field, depending on final wire design
|
|
348
|
+
|
|
349
|
+
If omitted, verifiers MAY try all candidate keys.
|
|
350
|
+
|
|
351
|
+
## 13.2 Format
|
|
352
|
+
|
|
353
|
+
`keyId` MAY be any stable opaque string.
|
|
354
|
+
|
|
355
|
+
Recommended:
|
|
356
|
+
- `sig-YYYY-MM`
|
|
357
|
+
- `enc-YYYY-MM`
|
|
358
|
+
- or ULID-based identifiers
|
|
359
|
+
|
|
360
|
+
It MUST be unique within the agent's key set.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## 14. Data Model
|
|
365
|
+
|
|
366
|
+
Recommended local store:
|
|
367
|
+
- `agent_keys`
|
|
368
|
+
|
|
369
|
+
Recommended fields:
|
|
370
|
+
- `agent_id`
|
|
371
|
+
- `key_id`
|
|
372
|
+
- `role`
|
|
373
|
+
- `algorithm`
|
|
374
|
+
- `public_key_multibase`
|
|
375
|
+
- `private_key_encrypted`
|
|
376
|
+
- `status`
|
|
377
|
+
- `valid_from`
|
|
378
|
+
- `valid_until`
|
|
379
|
+
- `revoked_at`
|
|
380
|
+
- `created_at`
|
|
381
|
+
- `updated_at`
|
|
382
|
+
|
|
383
|
+
Recommended identity metadata:
|
|
384
|
+
- `current_signing_key_id`
|
|
385
|
+
- `current_encryption_key_id`
|
|
386
|
+
- `key_set_version`
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## 15. API / Runtime Changes
|
|
391
|
+
|
|
392
|
+
Recommended runtime changes:
|
|
393
|
+
- key lookup by `agentId + role + status`
|
|
394
|
+
- verification helper that accepts candidate historical keys
|
|
395
|
+
- Agent Card generation from key set, not single key fields
|
|
396
|
+
- maintenance support for overlap transitions
|
|
397
|
+
- rotation admin/owner API
|
|
398
|
+
|
|
399
|
+
Recommended owner/admin APIs:
|
|
400
|
+
- `POST /api/tulpa/keys/rotate`
|
|
401
|
+
- `GET /api/tulpa/keys`
|
|
402
|
+
- `POST /api/tulpa/keys/:keyId/revoke`
|
|
403
|
+
|
|
404
|
+
These APIs are product/runtime concerns, not protocol requirements, but are strongly recommended.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## 16. Compatibility and Migration
|
|
409
|
+
|
|
410
|
+
## 16.1 Backward Compatibility
|
|
411
|
+
|
|
412
|
+
During migration from single-key agents:
|
|
413
|
+
- Agent Cards MAY advertise both legacy single-key fields and the new key-set structure
|
|
414
|
+
- receivers SHOULD support both during transition
|
|
415
|
+
|
|
416
|
+
## 16.2 Migration Path
|
|
417
|
+
|
|
418
|
+
1. add key-set fields to Agent Card
|
|
419
|
+
2. support rotation-aware verification in receivers
|
|
420
|
+
3. emit `keyId` on outbound messages
|
|
421
|
+
4. migrate storage from single current key to role-based key set
|
|
422
|
+
5. remove assumptions that `agentId` encodes current signing key
|
|
423
|
+
|
|
424
|
+
## 16.3 Legacy Agents
|
|
425
|
+
|
|
426
|
+
Receivers MUST continue to support legacy single-key agents during the migration window.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 17. Security Considerations
|
|
431
|
+
|
|
432
|
+
## 17.1 Compromise
|
|
433
|
+
|
|
434
|
+
If a signing key is compromised:
|
|
435
|
+
- rotation MUST support immediate revocation
|
|
436
|
+
- counterparties MUST refresh discovery data on verification miss
|
|
437
|
+
|
|
438
|
+
## 17.2 Replay
|
|
439
|
+
|
|
440
|
+
Key rotation does not replace nonce/timestamp replay protections.
|
|
441
|
+
|
|
442
|
+
Those protections remain mandatory.
|
|
443
|
+
|
|
444
|
+
## 17.3 Historical Trust
|
|
445
|
+
|
|
446
|
+
Historical verification does not imply ongoing trust.
|
|
447
|
+
|
|
448
|
+
Retired-key acceptance MUST be scoped to historical artifact verification, not new live messages.
|
|
449
|
+
|
|
450
|
+
## 17.4 Drift
|
|
451
|
+
|
|
452
|
+
All key-role logic MUST remain consistent across:
|
|
453
|
+
- the primary INK runtime
|
|
454
|
+
- the witness/auditability runtime
|
|
455
|
+
- test vectors
|
|
456
|
+
- lexicons
|
|
457
|
+
- docs
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## 18. Test Vectors
|
|
462
|
+
|
|
463
|
+
This spec requires new vector families for:
|
|
464
|
+
- active-key verification
|
|
465
|
+
- retired-key verification
|
|
466
|
+
- revoked-key rejection
|
|
467
|
+
- key-set version refresh behavior
|
|
468
|
+
- encrypted message decryption during overlap window
|
|
469
|
+
|
|
470
|
+
Minimum required cases:
|
|
471
|
+
- message signed by current key verifies
|
|
472
|
+
- message signed by retired key verifies as historical
|
|
473
|
+
- message signed by revoked key after `revokedAt` fails
|
|
474
|
+
- witness submit/query verifies against rotated key set
|
|
475
|
+
- stale cached key set refreshes successfully
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## 19. Rollout Plan
|
|
480
|
+
|
|
481
|
+
## Phase 1 ✓ (implemented 2026-03-25)
|
|
482
|
+
- ✓ `KeyEntry`, `KeyStatus`, `CandidateKey` types + Zod schemas (`src/models/key-entry.ts`)
|
|
483
|
+
- ✓ `AgentCardSchema` extended with optional `keys`, `currentSigningKeyId`, `currentEncryptionKeyId`, `keySetVersion`
|
|
484
|
+
- ✓ `agent_keys` SQLite table with lifecycle status, `identity` table gains key-set tracking columns
|
|
485
|
+
- ✓ `KeyStore` equivalent for agent_keys CRUD (implementer-specific path)
|
|
486
|
+
- ✓ `verifyInkSignatureWithKeys()` multi-key verification helper (`src/crypto/multi-key-verify.ts`)
|
|
487
|
+
- ✓ `verifyInkAuth` gains `resolveKeySet` parameter for multi-key transport auth, and `nonceStore: NonceStore | "deferred"` (required, fail-closed) for single-use nonce enforcement
|
|
488
|
+
- ✓ `PipelineContext.resolveKeySet` for multi-key message signature verification
|
|
489
|
+
- ✓ Receipt verification uses candidate key lists with active → retired ordering
|
|
490
|
+
- ✓ `extractCandidateKeys()` for Agent Card key extraction (`src/discovery/agent-card.ts`)
|
|
491
|
+
- ✓ `getAgentCard()` builds `keys` block from `KeyStore`
|
|
492
|
+
- ✓ Auto-migration: `seedFromIdentity()` on first wake-up
|
|
493
|
+
- ✓ `initialize()` inserts key entries alongside identity row
|
|
494
|
+
- ✓ Witness `verifyInkTransportAuth` signature accepts `resolveKeySet` (not yet wired)
|
|
495
|
+
- ✓ Test coverage: key-set schema, KeyStore CRUD, multi-key verification, end-to-end rotation vectors (see `test/ink-key-rotation.test.ts`)
|
|
496
|
+
|
|
497
|
+
## Phase 2 ✓ (implemented 2026-03-25)
|
|
498
|
+
- ✓ Key rotation APIs: `POST /tulpa/keys/rotate`, `GET /tulpa/keys`, `POST /tulpa/keys/:keyId/revoke`
|
|
499
|
+
- ✓ `keyId` emitted on outbound INK messages (auth header `keyId=` param + envelope `signingKeyId`)
|
|
500
|
+
- ✓ `hintKeyId` verification: try hinted key first, fallback to active → retired scan
|
|
501
|
+
- ✓ Agent Card cache with SQLite-backed TTL (1 hour default) and refresh-on-miss
|
|
502
|
+
- ✓ Integration tests for full rotated-message paths (6 e2e tests)
|
|
503
|
+
|
|
504
|
+
## Phase 3 ✓ (implemented 2026-03-25)
|
|
505
|
+
- ✓ Witness integration: `signingKeyId` passed to transport auth on witness submit
|
|
506
|
+
- ✓ `signingKeyId` recorded as a top-level field on `InkAuditEventSchema` for historical verification
|
|
507
|
+
- ✓ keyId semantics: auth header takes precedence, unknown keyId falls through, revoked keyId rejected
|
|
508
|
+
- ✓ Rotation observability: `signature.verified_retired`, `signature.revoked_rejected`, `key.rotated`, `key.revoked` audit event types
|
|
509
|
+
- ✓ `keyStatus` in `MultiKeyVerifyResult` for retired-key observability
|
|
510
|
+
- ✓ Audit bridge mappings: `key_rotated` → `key.rotated`, `key_revoked` → `key.revoked`
|
|
511
|
+
- ✓ Interop test vectors: 8 scenarios in `test-vectors/key-rotation.json`
|
|
512
|
+
- ✓ Phase 3 test cases in `test/ink-key-rotation.test.ts` (covers historical verification, revoked rejection, audit-event types)
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## 20. Open Questions
|
|
517
|
+
|
|
518
|
+
- Should `agentId` become DID-fragment-based, handle-based, or another stable logical identifier?
|
|
519
|
+
- Should historical keys live only in Agent Card, or also in ATP-linked records for verifiable history?
|
|
520
|
+
- Should `keyId` live in the signed JSON body or an authenticated transport header?
|
|
521
|
+
- What exact overlap duration should be mandatory for planned encryption-key rotation?
|
|
522
|
+
- Should retired signing keys remain indefinitely discoverable or move to a separate verified history surface?
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## 21. Recommendation
|
|
527
|
+
|
|
528
|
+
The recommended v1 direction is:
|
|
529
|
+
- stable logical `agentId`
|
|
530
|
+
- explicit role-based key sets in the Agent Card
|
|
531
|
+
- current + retired + revoked key lifecycle states
|
|
532
|
+
- rotation-aware verification
|
|
533
|
+
- historical verification continuity
|
|
534
|
+
|
|
535
|
+
This is the main remaining protocol design required to make INK feel finished.
|