Key Rotation
INK agents need to rotate cryptographic keys over time, for routine hygiene or emergency response to compromise. The key rotation protocol ensures that an agent’s identity remains stable across key changes while preserving verification of historical artifacts.
Core principle: keys rotate, identity does not.
Identity Model
An agent’s agentId is a stable logical identifier, independent of any particular signing key. When keys rotate, counterparties continue to address the same agent. Old receipts, audit events and witness records remain verifiable against retired keys.
Agent Card Key Advertisement
Agents advertise their key material in a keys block on the Agent Card. See the Agent Card spec for full schema details.
{ "agentId": "did:plc:alice#agent/tulpa-main", "protocol": "ink/0.1", "keys": { "signing": [ { "keyId": "sig-2026-03", "algorithm": "Ed25519", "publicKeyMultibase": "z6Mkf5rGMoatrSj1f...", "status": "active", "validFrom": "2026-03-25T00:00:00Z" }, { "keyId": "sig-2025-11", "algorithm": "Ed25519", "publicKeyMultibase": "z6MkhaXgBZDvotDkL...", "status": "retired", "validFrom": "2025-11-01T00:00:00Z", "validUntil": "2026-04-01T00:00:00Z" } ], "encryption": [ { "keyId": "enc-2026-03", "algorithm": "X25519", "publicKeyMultibase": "z6LSbysY2xFMRpGMh...", "status": "active", "validFrom": "2026-03-25T00:00:00Z" } ] }, "currentSigningKeyId": "sig-2026-03", "currentEncryptionKeyId": "enc-2026-03", "keySetVersion": 7}Top-Level Fields
| Field | Type | Description |
|---|---|---|
currentSigningKeyId | string | keyId of the current active signing key |
currentEncryptionKeyId | string | keyId of the current active encryption key |
keySetVersion | number | Monotonically increasing version; incremented on every rotation |
KeyEntry Schema
Each entry in the signing and encryption arrays:
type KeyEntry = { keyId: string; // unique within the agent's key set algorithm: "Ed25519" | "X25519"; // Ed25519 for signing, X25519 for encryption publicKeyMultibase: string; // z-prefixed base58btc public key status: "active" | "retired" | "revoked"; validFrom: string; // ISO 8601 datetime validUntil?: string; // ISO 8601 datetime (optional) revokedAt?: string; // ISO 8601 datetime (optional) revokeReason?: string; // human-readable reason (optional)};Key Statuses
| Status | New outbound messages | Inbound verification | Historical verification |
|---|---|---|---|
active | Yes | Yes | Yes |
retired | No | Yes (during rotation grace period; receivers MAY refuse based on local policy) | Yes (within validity window) |
revoked | No | Never | Only artifacts signed before revokedAt (local policy) |
Verification
Authority rule (normative)
The Agent Card signing key set, once observed, is authoritative. A conforming receiver MUST:
- Verify the signature against entries in the sender’s Agent Card
keys.signingset, iteratingactivethenretired. Never iteraterevoked. - If any entry verifies, accept and record which
keyIdwas used. - If no entry verifies, reject. Do not fall through to any other key source.
Only when the receiver has never observed an Agent Card for the sender may it use a bootstrap path, a public key derived from an agent-ID scheme, or a key stored locally from an earlier first-contact handshake. This is the trust-on-first-use window and ends the first time a valid Agent Card is observed for that sender.
Three failure modes this rule closes:
- Stolen old key. An attacker holding a key the sender has since marked
retiredorrevokedcannot authenticate, even if a receiver still has the old key in its connection store. - Fallback shadowing. A receiver that “tries the authoritative set, then falls back to a single-key lookup” can have the fallback return a pre-rotation key. The rule forbids fallback after the authoritative set has spoken.
- Bootstrap persistence. Identity schemes that derive a public key from the agent ID freeze that key at creation. Limiting its use to first-contact prevents indefinite acceptance.
Signing Verification Order
When verifying an inbound message signature:
- If the request carries a
keyIdhint, try the matchingactiveorretiredkey first. - Try the sender’s
activesigning keys in card order. - Try the sender’s
retiredsigning keys in card order. - Reject if no candidate verifies.
Publishers SHOULD list currentSigningKeyId first inside keys.signing so it
is the first key tried by step 2. The keyId hint header is the explicit way
to short-circuit the scan when the sender knows which key it signed with.
Historical Verification
For receipts, audit events and witness submissions:
- Retired keys are valid for verification if the artifact timestamp falls within the key’s validity window (
validFromtovalidUntil) - Revoked keys MUST NOT verify any signature, including artifacts whose timestamp predates
revokedAt. Revocation is a trust statement and applies historically. Useretiredif a key should remain valid for past traffic.
Encryption
- Senders MUST encrypt to the recipient’s current active encryption key
- During rotation overlap, receivers SHOULD support decryption with both the current and immediately previous retired encryption key
- Recommended minimum overlap for planned rotation: 7 days
Rotation Flow
Planned Rotation
Emergency Rotation
For suspected key compromise:
- Publish updated Agent Card immediately
- Mark compromised key
revokedwithrevokedAttimestamp - Increment
keySetVersion - Begin signing with new key immediately
Emergency revocation may break in-flight encrypted delivery. This is acceptable.
Authentication Header
Outbound INK messages SHOULD include the signing keyId in the authorization header:
Authorization: INK-Ed25519 <base64url-signature> keyId=sig-2026-03This lets receivers skip trial-verification across all candidate keys. If the keyId is unknown or omitted, receivers fall back to the standard verification order.
See Authentication for full header details.
Cache Invalidation
Implementations SHOULD cache discovered key sets but MUST refresh when:
- Signature verification fails for all cached active keys
- A message references an unknown
keyId - A newer
keySetVersionis observed - Encryption to the current key fails due to key mismatch
Recommended cache TTL: 1 hour.
Rotation Advisory Message
Implementations MAY define a vendor-specific advisory message — for example, vendor.example.key_rotation — to nudge counterparties to refresh their cached Agent Card after a planned rotation. A typical shape looks like:
{ "type": "vendor.example.key_rotation", "from": "did:plc:alice#agent/tulpa-main", "to": "did:plc:bob#agent/tulpa-main", "newKeySetVersion": 7, "rotatedSigningKeyIds": ["sig-2025-11"], "rotatedEncryptionKeyIds": [], "timestamp": "2026-03-25T00:00:00Z", "nonce": "abc123"}This is not part of the INK v0.1 wire-type registry (see Wire Types). It is purely advisory: the Agent Card remains the canonical source of truth for key material, and receivers SHOULD treat any such hint as a cue to refresh their cached Agent Card. Agents that want this nudge can ship it under their own namespace; agents that don’t will discover the rotation on their next Card fetch.
Historical Key Retention
Historical keys used for verification SHOULD remain available for at least 90 days. Indefinite retention with appropriate status marking is recommended.
If a system cannot retain historical keys indefinitely in the live Agent Card, it MUST provide a documented verified history surface.
Bootstrap Key Handling
After key rotation, the bootstrap key embedded in the agentId is no longer accepted as a signing fallback. Witness nodes fetch the sender’s Agent Card to resolve current signing keys rather than falling back to the bootstrap key. This prevents a compromised bootstrap key from being used to forge messages after a rotation has occurred.
Legacy Compatibility
Single-Key Agent Cards
Agent Cards without a keys block use the top-level publicKeyMultibase field directly as the sole signing key. Receivers MUST continue to support this single-key format during the migration window.
Key ID Hints
keyId is optional and strongly recommended. Receivers use it as a verification hint, then fall back to the standard active-then-retired key scan when it is omitted or unknown. Bare INK-Ed25519 <signature> headers remain valid for single-key and legacy peers.
Observability
Key rotation events are recorded in the audit trail:
| Event Type | Trigger |
|---|---|
key.rotated | New key activated, previous key retired |
key.revoked | Key marked as revoked |
signature.verified_retired | Message verified against a retired key |
signature.revoked_rejected | Message rejected due to revoked key |