Rotating Keys
Supersession is how you rotate keys or upgrade your identity while maintaining continuity. Your fingerprint changes, but your identity's history remains intact.
Why Supersede?
1. Security Hygiene (Recommended: Yearly)
Even if your key isn't compromised, periodic rotation limits exposure.
Scenario: You've been using the same Ed25519 key for 2 years. It's time to rotate.
atp supersede --old identity.json --reason key-rotation2. Key Compromise (Emergency)
Your private key was accessed by unauthorized parties.
Scenario: Your laptop was stolen. You suspect the attacker extracted your key file.
atp supersede --old identity.json --reason key-compromised3. Algorithm Upgrade
Migrating to stronger cryptography (e.g., Ed25519 → Dilithium for quantum resistance).
Scenario: It's 2030, and quantum computers are advancing. You want post-quantum safety.
atp supersede --old identity.json \
--reason algorithm-upgrade \
--new-private-key dilithium-key.pem4. Metadata Update
Changing your name, wallet address, or social links.
Scenario: You rebranded from "ResearchBot" to "ScholarAgent."
atp supersede --old identity.json \
--reason metadata-update \
--name ScholarAgentHow Supersession Works
The supersession document IS the new identity. It contains the new name, keys, and metadata alongside a reference to the old identity being superseded.
{
"v": "1.0",
"t": "super",
"target": {
"f": "xK3jL9mN1qQ9pE4tU6u1fGRjwNWwtnQd4fG4eISeI6s",
"ref": {
"net": "bip122:000000000019d6689c085ae165831e93",
"id": "6ffcca0cc29da514e784b27155e68c3d4c1ca2deeb6dc9ce020a4d7e184eaa1c"
}
},
"n": "MyAgent",
"k": [
{
"t": "dilithium",
"p": "<2603 base64url chars — new Dilithium public key>"
}
],
"reason": "algorithm-upgrade",
"ts": 1738600000,
"s": [
{
"f": "xK3jL9mN1qQ9pE4tU6u1fGRjwNWwtnQd4fG4eISeI6s",
"sig": "<86 base64url chars — old Ed25519 signature>"
},
{
"f": "aBtxA94XweOEmkvNbrfw-KGbLA1OX2p7jJ0OHyoLTF0",
"sig": "<4391 base64url chars — new Dilithium signature>"
}
]
}Key fields:
t: "super": Document type is supersession (this IS the new identity)target: References the old identity (f+ref)n,k,m: New identity attributesreason: Why this supersession is happenings: Exactly 2 signatures —s[0]from old identity,s[1]from new identity
The Dual Signature Rule
The supersession document must be signed by both the old and new identity.
Why?
Proof of handoff:
- Old identity signature (
s[0]) → Authorizes the handoff: "I'm transferring authority to the new key" - New identity signature (
s[1]) → Accepts the handoff: "I accept authority from the old key"
No one can forge a supersession without both private keys. The signatures are in canonical order: old first, new second.
How It Works
// Step 1: Build supersession document (unsigned)
const unsignedSupersession = {
v: '1.0',
t: 'super',
target: {
f: oldFingerprint,
ref: {
net: 'bip122:000000000019d6689c085ae165831e93',
id: oldIdentityTxid
}
},
n: 'MyAgent',
k: [
{
t: 'dilithium',
p: Buffer.from(newKeyPair.publicKey).toString('base64url')
}
],
reason: 'algorithm-upgrade',
ts: Math.floor(Date.now() / 1000)
};
// Step 2: Serialize (canonical JSON in real implementations)
const canonicalBytes = Buffer.from(JSON.stringify(unsignedSupersession), 'utf8');
// Step 3: Prepend domain separator
const domainSep = Buffer.from('ATP-v1.0:', 'utf8');
const messageToSign = Buffer.concat([domainSep, canonicalBytes]);
// Step 4: Sign with OLD identity key
const oldSigBytes = nacl.sign.detached(messageToSign, oldSecretKey);
// Step 5: Sign with NEW identity key
const newSigBytes = dilithium.sign(messageToSign, newSecretKey);
// Step 6: Attach both signatures (order is normative: old first, new second)
const supersession = {
...unsignedSupersession,
s: [
{ f: oldSigningKeyFingerprint, sig: Buffer.from(oldSigBytes).toString('base64url') },
{ f: newSigningKeyFingerprint, sig: Buffer.from(newSigBytes).toString('base64url') }
]
};Creating a Supersession (CLI)
Key Rotation (New Keypair)
atp supersede --old identity.json --reason key-rotationThis:
- Generates a new Ed25519 keypair
- Creates a supersession document referencing the old identity
- Signs with both old and new keys
- Outputs
supersession.json
Algorithm Upgrade
atp supersede --old identity.json \
--reason algorithm-upgrade \
--new-private-key dilithium-key.pemMetadata Update Only
atp supersede --old identity.json \
--reason metadata-update \
--name NewAgentName \
--meta twitter:NewHandleNote: For metadata-only updates, the CLI reuses the old key as the new key. This creates a supersession without changing the fingerprint.
Compromise: What You Can (and Can't) Do
Supersession is a cryptographic handoff. By design, it requires both signatures:
s[0]from the old identity (authorizes the transfer)s[1]from the new identity (accepts the transfer)
There is no single-signature supersession mode in ATP v1.0.
If you still control the old key
Supersede immediately with reason "key-compromised", and remove any compromised secondary keys (reason "key-removal" if applicable). Time matters: only the first valid supersession from a given identity is canonical.
If you no longer control the old key
You cannot supersede.
Your options are:
- Revoke (if you control any non-expired key from any identity in the supersession chain). Revocation is a poison pill: it kills the entire chain.
- Start a new identity from scratch (new genesis fingerprint), and optionally link to the old identity in metadata and out-of-band announcements.
What Happens to the Old Identity?
It Still Exists
Inscriptions are permanent. The old identity remains on Bitcoin forever.
It's Marked Superseded
Explorers display the supersession chain:
Identity A (created 2024-02-01)
↓ superseded by
Identity B (created 2025-06-15)
↓ superseded by
Identity C (created 2026-02-13) ← currentAttestations Stay
Attestations to the old identity remain valid. They're historical facts:
- "Agent X vouched for Identity A on 2024-05-10" is still true
- Applications can choose to transfer trust to the new identity via the supersession chain
It's No Longer Active
The old fingerprint is retired. You should:
- Stop using it for new operations
- Update your profiles to reference the new fingerprint
- Notify contacts of the change
Verification Chain
Applications should walk the supersession chain to find the current identity:
atp verify <old-fingerprint> --follow-supersessionsThis:
- Fetches the old identity
- Checks if it has been superseded (via explorer API)
- Fetches the supersession document
- Verifies both signatures
- Repeats until reaching the current (non-superseded) identity
Manual chain walking:
async function getCurrentIdentity(fingerprint) {
let current = await fetchIdentity(fingerprint);
while (true) {
const supersession = await findSupersession(current.fingerprint);
if (!supersession) break;
// Verify dual signature
if (!verifySupersession(supersession, current)) {
throw new Error('Invalid supersession chain');
}
current = supersession;
}
return current;
}Best Practices
✅ Do
- Rotate periodically (yearly recommended)
- Keep old keys until supersession is inscribed (you need both to sign)
- Announce transitions publicly (Twitter, GitHub, your website)
- Test the supersession before inscribing (verify signatures locally)
- Document the reason (use
--reasonflag)
❌ Don't
- Don't delete old keys immediately (you may need to revoke if something goes wrong)
- Don't supersede too frequently (spamming the chain reduces trust)
- Don't skip verification (always verify both signatures before inscribing)
- Don't reuse supersession TXIDs (each supersession must reference a unique old identity)
Supersession vs. Revocation
| Aspect | Supersession | Revocation |
|---|---|---|
| Purpose | Key rotation, upgrade | Emergency shutdown |
| Effect | New identity continues the old one | Identity chain dies permanently |
| Attestations | Transferred to new identity (via chain) | Lost forever |
| Reversible? | No (but you can supersede the supersession) | No (permanent death) |
| When to use | Routine key hygiene, algorithm upgrades | Catastrophic compromise, identity retirement |
Rule of thumb: Use supersession for normal operations, revocation only as a last resort.
See Emergency Revocation for details.
Supersession Scenarios
Scenario 1: Routine Key Rotation
Every year, rotate your key.
# Year 1
atp identity create --name ResearchAgent
# Year 2
atp supersede --old identity.json --reason key-rotation
# Year 3
atp supersede --old supersession-year2.json --reason key-rotationResult: A clean supersession chain with annual rotations.
Scenario 2: Algorithm Migration
Move from Ed25519 to Dilithium.
# Generate new Dilithium key
atp key generate --type dilithium --output dilithium.pem
# Supersede
atp supersede --old identity.json \
--reason algorithm-upgrade \
--new-private-key dilithium.pemResult: Quantum-resistant identity with historical Ed25519 chain.
Scenario 3: Multi-Key to Single-Key
Simplify from a multi-key identity to a single key.
// Old identity (multi-key)
{
"t": "id",
"k": [
{ "t": "ed25519", "p": "<key1>" },
{ "t": "ed25519", "p": "<key2>" }
],
"s": { "f": "<key1-fingerprint>", "sig": "<signature>" }
}
// Supersession to single key
{
"t": "super",
"target": { "f": "<old-fingerprint>", "ref": { "net": "bip122:...", "id": "<old-txid>" } },
"k": [ { "t": "ed25519", "p": "<new-key>" } ],
"reason": "key-rotation",
"s": [
{ "f": "<old-signing-key-fingerprint>", "sig": "<old-identity-signature>" },
{ "f": "<new-signing-key-fingerprint>", "sig": "<new-identity-signature>" }
]
}Note: Only two signatures are required: one from the old identity (any one of its keys) and one from the new identity (any one of its keys).
Inspecting a Supersession
atp identity show supersession.jsonOutput:
Name: MyAgent
Version: 1.0
Type: super
Keys: dilithium (+ optional secondary keys)
Fingerprint (new): aBtxA94XweOEmkvNbrfw-KGbLA1OX2p7jJ0OHyoLTF0
Target (old): xK3jL9mN1qQ9pE4tU6u1fGRjwNWwtnQd4fG4eISeI6s
ref: bip122:000000000019d6689c085ae165831e93 / abc123...def456
Signatures: 2 (old identity + new identity)
Timestamp (ts): 2026-02-13 07:45:00 UTC (informational)