Skip to content

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?

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.

bash
atp supersede --old identity.json --reason key-rotation

2. Key Compromise (Emergency)

Your private key was accessed by unauthorized parties.

Scenario: Your laptop was stolen. You suspect the attacker extracted your key file.

bash
atp supersede --old identity.json --reason key-compromised

3. 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.

bash
atp supersede --old identity.json \
  --reason algorithm-upgrade \
  --new-private-key dilithium-key.pem

4. Metadata Update

Changing your name, wallet address, or social links.

Scenario: You rebranded from "ResearchBot" to "ScholarAgent."

bash
atp supersede --old identity.json \
  --reason metadata-update \
  --name ScholarAgent

How 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.

json
{
  "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 attributes
  • reason: Why this supersession is happening
  • s: 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

javascript
// 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)

bash
atp supersede --old identity.json --reason key-rotation

This:

  1. Generates a new Ed25519 keypair
  2. Creates a supersession document referencing the old identity
  3. Signs with both old and new keys
  4. Outputs supersession.json

Algorithm Upgrade

bash
atp supersede --old identity.json \
  --reason algorithm-upgrade \
  --new-private-key dilithium-key.pem

Metadata Update Only

bash
atp supersede --old identity.json \
  --reason metadata-update \
  --name NewAgentName \
  --meta twitter:NewHandle

Note: 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:

  1. 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.
  2. 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) ← current

Attestations 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:

bash
atp verify <old-fingerprint> --follow-supersessions

This:

  1. Fetches the old identity
  2. Checks if it has been superseded (via explorer API)
  3. Fetches the supersession document
  4. Verifies both signatures
  5. Repeats until reaching the current (non-superseded) identity

Manual chain walking:

javascript
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 --reason flag)

❌ 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

AspectSupersessionRevocation
PurposeKey rotation, upgradeEmergency shutdown
EffectNew identity continues the old oneIdentity chain dies permanently
AttestationsTransferred to new identity (via chain)Lost forever
Reversible?No (but you can supersede the supersession)No (permanent death)
When to useRoutine key hygiene, algorithm upgradesCatastrophic 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.

bash
# 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-rotation

Result: A clean supersession chain with annual rotations.

Scenario 2: Algorithm Migration

Move from Ed25519 to Dilithium.

bash
# 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.pem

Result: Quantum-resistant identity with historical Ed25519 chain.

Scenario 3: Multi-Key to Single-Key

Simplify from a multi-key identity to a single key.

json
// 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

bash
atp identity show supersession.json

Output:

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)

← Previous: Key Management | Next: Emergency Revocation →

Released under the MIT License.