I've started building an ATproto app. And since I'm a sicko who loves reading documentation, I'm simultaneously diving into docs to understand how the ecosystem works; currently, I'm on The AT Stack.

Overall, I think I have a pretty good understanding:

  • PDSes are data storage

  • Relays are event queues

  • Taps are essentially event listeners with backfilling

  • App Views handle materialized views (or, precomputed results of feeds)

    • Shoutout to Martin Kleppmann's Designing Data-Intensive Applications for explaining what this means

Cool, cool, cool. All good.

Except, this one brief and simple phrase borked my understanding:

did:plc is a self-authenticating Decentralized Identifier

Okay... I know what the word self means, right? When an action is preceded by the word "self," it means no other entity was relied upon to execute that action. Self-governing, self-replicating, self-contained, self-funded - it's just me, myself, and I.

But according to the docs:

PLC operations are stored in a directory (currently run at plc.directory) which is a centralized service that validates operations, stores them, and serves those operations...

So:

  1. 1.

    What does self mean in this instance?

  2. 2.

    And, what exactly is being authenticated?

After some more digging and a lengthy conversation with Gemini, I think I have an understanding.

Here's my breakdown of how ATproto DIDs work, and what we mean when we say they are self-authenticating:

First: What are DIDs?

DIDs are IDs. But they're also hashes of the initial operation that resulted in the DID itself!

Let's look at my own for specifics:

did:plc:o6hf54rkiurn3wmai7dr33dc

The last clause of my DID, o6hf54rkiurn3wmai7dr33dc, is actually a hash of the original operation that created this very same DID.

How it works:

  • The operation to create my DID is:

{
  "prev": null,

  "type": "plc\_operation",

  "services": {
    "atproto_pds": {

      "type": "AtprotoPersonalDataServer",

      "endpoint": "https://polypore.us-west.host.bsky.network"
    }
  },
  "alsoKnownAs": [
    "at://kat-kime.bsky.social"
  ],
  "rotationKeys": [
    "did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg",
    "did:key:zQ3shpKnbdPx3g3CmPf5cRVTPe1HtSwVn5ish3wSnDPQCbLJK"
  ]
  "verificationMethods": {
    "atproto": "did:key:zQ3shhX2aH6szJj9NrCLQL3hBAYqZsnSMhs2swRYDnAtN1Th2"
  }
  • This object was serialized into bytes using DAG-CBOR

    • DAG-CBOR enforces a specific ordering of keys to ensure consistent output in all serializations

  • The Bluesky client used a private key to sign the bytes, resulting in the key/value pair:

sig: "8KE6tXu-S4zyN3uu1SBjJqIWQcZPWkWnR4T5ZLnOa28EvqjrMlxHG0hUND1BxOOVeeFJcsU_7ucm1tc7-QLkOQ"
  • This was added to the operation, thus signing it

  • The signed operation was, again, serialized into DAG-CBOR bytes

  • A SHA-256 hash was run on the bytes and the output was encoded into base32, resulting in the string:

o6hf54rkiurn3wmai7dr33dcuqghspg36o5npejf4osl6ji4hrbq
  • The first 24 characters were extracted and appended to the did:plc prefix, resulting in my final DID:

did:plc:o6hf54rkiurn3wmai7dr33dc

Finally, this DID was pushed to the PLC directory to store an append-only log of the creation operation, as well as all future operations performed on the DID.

So, my DID is an ID.

But it's also a hash of the original operation that created the DID! And, if you visit plc.directory/did:plc:o6hf54rkiurn3wmai7dr33dc/log/audit it's a pointer to the log that stores a history of all operations performed on the DID.

(Here's a quick Python program you can run to verify this yourself)

Second: Why do we call DIDs self-authenticating?

Okay, so here's the thing -

It's not the actual DID that does the authenticating. As we saw previously, my DID is only a truncation of the final base32 encoding of the original hashed operation. And the encoding itself only represents the initial genesis operation.

So when we say a DID is self-authenticating, what we're actually saying is that this identifier points to an append-only ledger, similar to how a git hash points to a code commit. And it's this ledger that contains all the content needed to verify its own validity.

How the ledger works:

Each log in the ledger has a prev pointer, pointing to the previous state of the ledger (except the initial operation, which has a prev pointer of null)

This state is represented as a content identifier, or CID, which is created by:

  1. 1.

    Serializing the operation into DAG-CBOR bytes

  2. 2.

    Running a SHA-256 hash

  3. 3.

    Wrapping the hash into a container that includes:

    1. 1.

      The CID version

    2. 2.

      The DAG-CBOR codec identifier

    3. 3.

      The hash

  4. 4.

    Encoding the CID wrapper into base32

Because each entry in the ledger points to a hash of the previous state of the ledger, you can iterate through each entry and verify its contents all the way back to the original genesis operation. If a single byte of the content has changed, the hashes will not match.

So, this is what we mean when we say a DID is self-authenticating:

The DID points to an append-only ledger, where each entry contains the previous state of the ledger. You don't need any outside authority to verify the contents of the ledger; just run a program and do it yourself.