{"id":41685267,"url":"https://github.com/fedi-e2ee/public-key-directory-specification","last_synced_at":"2026-01-31T00:02:49.113Z","repository":{"id":252141988,"uuid":"812178125","full_name":"fedi-e2ee/public-key-directory-specification","owner":"fedi-e2ee","description":"Specification for a Fediverse Directory Server for Public Keys","archived":false,"fork":false,"pushed_at":"2026-01-24T20:53:50.000Z","size":538,"stargazers_count":155,"open_issues_count":5,"forks_count":3,"subscribers_count":13,"default_branch":"main","last_synced_at":"2026-01-25T06:46:50.050Z","etag":null,"topics":["fediverse","key-transparency"],"latest_commit_sha":null,"homepage":"https://publickey.directory","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fedi-e2ee.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-06-08T06:50:01.000Z","updated_at":"2026-01-24T20:53:53.000Z","dependencies_parsed_at":"2024-08-21T23:32:27.379Z","dependency_job_id":"bedbeddd-003c-4e09-9955-ebc56fceed21","html_url":"https://github.com/fedi-e2ee/public-key-directory-specification","commit_stats":null,"previous_names":["fedi-e2ee/public-key-directory-specification"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/fedi-e2ee/public-key-directory-specification","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedi-e2ee%2Fpublic-key-directory-specification","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedi-e2ee%2Fpublic-key-directory-specification/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedi-e2ee%2Fpublic-key-directory-specification/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedi-e2ee%2Fpublic-key-directory-specification/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fedi-e2ee","download_url":"https://codeload.github.com/fedi-e2ee/public-key-directory-specification/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedi-e2ee%2Fpublic-key-directory-specification/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28923745,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T22:32:35.345Z","status":"ssl_error","status_checked_at":"2026-01-30T22:32:31.927Z","response_time":66,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fediverse","key-transparency"],"created_at":"2026-01-24T19:21:53.978Z","updated_at":"2026-01-31T00:02:49.096Z","avatar_url":"https://github.com/fedi-e2ee.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Public Key Directory Server Specification\n\nThis repository contains the specification for a **Public Key Directory** for the Fediverse.\n\n\u003e [!CAUTION]\n\u003e This is still a work in progress.\n\u003e \n\u003e There may be bugs. Some things may be under-specified, or there could be subtle contradictions.\n\u003e [Please tell us](https://github.com/fedi-e2ee/public-key-directory-specification/issues/new) if we made a mistake.\n\n## What Is This All About?\n\n\u003e [!NOTE]\n\u003e If you're more technical, [feel free to skip this section](#our-proposal).\n\nThis project is an infrastructure component to improve the privacy of the Fediverse. Its intended audience is software\ndevelopers, system administrators, security researchers, academics, cryptographers, and technology experts.\n\nIf you're not already familiar with the Fediverse (e.g., Mastodon), [The Verge](https://www.theverge.com/24063290/fediverse-explained-activitypub-social-media-open-protocol) \n([archived](https://archive.is/TuNUu)) tried to explain it in 2024.\n\nCurrently, Direct Messages (DMs) on the Fediverse are like postcards: Server admins and malicious hackers can read them,\nif they want to. Law enforcement can also compel server admins to disclose them if they want to prosecute you, and there\nis little recourse for them except to comply. (Unlike large tech companies, most instance admins do not have a large\nlegal defense fund to fight the government in court.)\n\nThe architects of the Fediverse are investigating a technique called [end-to-end encryption](https://github.com/swicg/activitypub-e2ee)\nto alleviate this privacy risk. This is like upgrading from postcards to sealed envelopes that only the recipient can\nopen. This envelope upgrade requires careful use of math that involves something called a \"public key\". You can think of\nit as a special lock that only the intended party can open.\n\n### Where does this project come in?\n\nThe hardest part of designing end-to-end encryption for the Fediverse is actually a **Key management** problem, which\ncan be summed up as one question:\n\n\u003e How do you know which public key belongs to a stranger you want to chat privately with?\n\nHow ever you decide to initially answer that question, the obvious follow-up question is:\n\n\u003e How do you know that you weren't deceived?\n\nAnd if you repeat this exercise, you will eventually reinvent a trust model for a public key infrastructure.\n\n### Why This Problem Is Harder Than It Looks\n\nThere are some obvious questions that arise when first faced with this problem, depending on your technical background.\n\n#### Why not just a simple directory?\n\nA simple directory is quick and easy: Just look up a username and get their public key. ActivityPub already offers such\na mechanism with [webfinger](https://webfinger.net/). Why not just rely on that?\n\nThe problem is: You have to **completely trust** whoever runs that directory. If a simple directory operator is \ncompromised, or decides to be malicious, they can silently hand you the wrong key for someone you want to message, and\nyou'd have no way to detect it. The key you think belongs to Alice might actually belong to an attacker.\n\n#### Why not just use Certificates and Certificate Authorities?\n\nThis creates a power structure where a few trusted entities (Authorities) have the capability to impersonate anyone in\nthe ecosystem. This gives hackers and hostile governments easy targets to prioritize, and is fundamentally incompatible\nwith the goals and culture of the Fediverse.\n\n#### Why not use an existing solution?\n\nThe technical details matter a lot. Read [the threat model](Specification.md#threat-model) to understand more about what\nfeatures and security properties we're trying to provide, which isn't compatible with existing designs.\n\n(This README only gets more technical from this point on.)\n\n## Our Proposal\n\nOur solution is to require all relevant actions (public key enrollment and revocation) be published immediately onto an \nappend-only data structure (i.e., a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree)). In the cryptographic\nliterature, this is called \"Key Transparency\".\n\nThe Public Key Directory vends a user's public keys (which originate from the user's device) that can be used with \ndigital signature algorithms, and includes a machine-verifiable proof of when each public key was enrolled.\n\nThis machine-verifiable proof is useful for establishing a baseline, minimal level of trust that a given public key is\ncorrect for the party you wish to talk to. That is to say: **It keeps the directory honest.**\n\nAdditional manual key verification mechanisms (key fingerprints, safety numbers, etc.) are out-of-scope but totally \npermitted for technical users in higher-level protocols. Really, we're trying to do better than Trust on First Use \n(TOFU), so [Johnny can finally encrypt](https://people.eecs.berkeley.edu/~tygar/papers/Why_Johnny_Cant_Encrypt/OReilly.pdf). \n\nOther applications can build atop our Public Key Directory design to build advanced use cases (i.e., authenticated key \nexchanges for end-to-end encryption).\n\nIt's worth keeping in mind that the Public Key Directory isn't *just* the Merkle Tree, it's an API built on top of a\nMerkle Tree. To that end, you can query the API to retrieve every currently-trusted public key for a user, rather than\nhaving to manually parse this information out of the data stored in the underlying data structure.\n\n### How Does This Help Non-Technical Users?\n\n**This doesn't *directly* help non-technical users,** but it does help developers solve a difficult problem so they can\nfocus on making software better and easier to use, which (in turn) helps everyone.\n\nThe Public Key Directory is a building block for developers. Our immediate audience for this specific component is \nnecessarily somewhat technical.\n\nHowever, the projects that build *atop* this building block should take pains to minimize the friction for non-technical\nusers. (That includes the other projects we will be opening in this GitHub organization!)\n\n### What kind of keys are vended by the Public Key Directory?\n\nPublic keys meant for verifying digital signatures, not encryption keys.\n\nTo integrate the Public Key Directory with a broader E2EE project, you can use the signature verification keys to verify\na signed [key package (in MLS parlance)](https://www.rfc-editor.org/rfc/rfc9420.html#name-key-packages). This provides\nassurance that the \"key package\" your software is using to start a private chat is actually owned by your friend.\n\n### Does the Public Key Directory publish anything except those public keys?\n\n**Yes!** The Public Key Directory additionally publishes [Auxiliary Data](Specification.md#auxiliary-data), which allows\ndevelopers a convenient way to build key transparency into their own systems by building atop ours.\n\n### How does Key Transparency help the trust issue?\n\nIt proves [everyone sees the same thing](https://defuse.ca/triangle-of-secure-code-delivery.htm#:~:text=are%20successfully%20attacked.-,Userbase%20Consistency%20Verification%3A,-Users%20of%20the).\n\nTransparency systems allow you to prove that everyone has an identical view of history. This means the directory cannot\nlie about its contents without detection. **This keeps everyone honest.**\n\nThe mapping of public keys (and auxiliary data) to ActivityPub actors is entirely deterministic: If you replayed the \nentire Transparency log from the first entry to the current latest, starting with a blank slate, you will always arrive\nat the same final mapping.\n\n### How the Pieces Fit Together\n\n```mermaid\nflowchart TB\n    subgraph Users[\"End Users\"]\n        Alice[\"Alice's Client\"]\n        Bob[\"Bob's Client\"]\n    end\n\n    subgraph Fediverse[\"Fediverse Instances\"]\n        ServerA[\"Instance A\u003cbr/\u003e(e.g., mastodon.social)\"]\n        ServerB[\"Instance B\u003cbr/\u003e(e.g., hachyderm.io)\"]\n    end\n\n    subgraph PKD[\"Public Key Directory\"]\n        API[\"JSON REST API\u003cbr/\u003e(read-only queries)\"]\n        Inbox[\"ActivityPub Inbox\u003cbr/\u003e(Protocol Messages)\"]\n        State[\"Current Key State\u003cbr/\u003e(valid keys per Actor)\"]\n        TLog[\"Transparency Log\u003cbr/\u003e(append-only Merkle tree)\"]\n    end\n\n    subgraph Federation[\"PKD Federation\"]\n        PKD2[\"Other PKD Instances\"]\n    end\n\n    Auditors[\"Auditors \u0026 Verifiers\"]\n\n    %% User to Instance flows\n    Alice --\u003e|\"HPKE-encrypted\u003cbr/\u003eProtocol Messages\"| ServerA\n    Bob --\u003e|\"HPKE-encrypted\u003cbr/\u003eProtocol Messages\"| ServerB\n\n    %% Instance to PKD flows\n    ServerA --\u003e|\"HTTP Signatures +\u003cbr/\u003eAddKey, RevokeKey, etc.\"| Inbox\n    ServerB --\u003e|\"HTTP Signatures +\u003cbr/\u003eAddKey, RevokeKey, etc.\"| Inbox\n\n    %% Direct user revocation (bypass instance)\n    Alice -.-\u003e|\"RevokeKeyThirdParty\u003cbr/\u003e(emergency revocation)\"| API\n\n    %% PKD internal flows\n    Inbox --\u003e State\n    State --\u003e TLog\n\n    %% Query flows\n    ServerA \u0026 ServerB --\u003e|\"Query public keys\u003cbr/\u003efor other users\"| API\n    API --\u003e State\n\n    %% Federation\n    TLog \u003c--\u003e|\"Checkpoint\u003cbr/\u003e(cross-PKD Merkle roots)\"| PKD2\n\n    %% Auditing\n    TLog --\u003e|\"Verify append-only\u003cbr/\u003ehistory\"| Auditors\n```\n\n* **Users** generate keys locally and send encrypted [Protocol Messages](Specification.md#protocol-messages) through\n  their Fediverse instance\n* **Instances** add HTTP Message Signatures ([RFC 9421](https://www.rfc-editor.org/rfc/rfc9421.html)) and relay messages\n  to the Public Key Directory (PKD)\n* **PKD** validates messages, updates key state, and commits everything to the transparency log\n* **Disaster recovery** that can [pass the Mud Puddle test](https://blog.cryptographyengineering.com/2012/04/05/icloud-who-holds-key/)\n  is baked into our design:\n  * Third-party revocation allows users to revoke compromised keys directly, bypassing a potentially malicious\n    instance\n  * Recovery is enabled through [BurnDown](Specification.md#burndown); users can elect to become \n    [Fireproof](Specification.md#fireproof) to become immune to BurnDown\n* **Federation** enables multiple PKDs to cross-verify via Checkpoint messages\n* **Auditors** can independently verify the append-only log hasn't been tampered with\n\n## Our Guiding Principles\n\nAll design decisions for this proposal have been influenced by the following guiding principles.\n\n1. Build for people, and\n2. Security over legacy\n\n### Build for People\n\nThe main goal of this project is to enable more people to securely communicate with each others.\nFrom this it follows that we\n\n* don't require any expert knowledge from the users of this system.\n* minimize the number of steps a user has to take to use this system securely.\n* value the privacy of the users, by only storing the minimal amount of information necessary and make it possible to delete data when the user demands it.\n* clearly communicate errors and incidents to the users and by doing so give them a proper understanding of their security state.\n\nAs a side note, we don't consider companies as people.\n\n### Security Over Legacy\n\nWe want to build a system that solves key management for people, nothing less and nothing more.\nThere are many ways to solves this problem and many existing solutions which could become part of our solution.\nBut we want to take the opportunity to focus on security and verifiability.\nThis means if we have the choice we will not take an existing solution, when this solution leads to an unwarranted increase in complexity or a security compromise. Even if this solution is an established standard and used by everyone else.\n\n## Documents In Scope\n\n* [Architecture](Architecture.md)\n  \\- This document succinctly describes how the Public Key Directory fits into the Fediverse.\n* **[Specification](Specification.md)**\n  \\- This document contains the specification text in its entirety.\n  1. [Introduction](Specification.md#introduction)\n  2. [Concepts](Specification.md#concepts)\n  3. [Threat Model](Specification.md#threat-model)\n  4. [Protocol Messages](Specification.md#protocol-messages)\n  5. [The Federated Public Key Directory](Specification.md#the-federated-public-key-directory)\n  6. [Cryptography Protocols](Specification.md#cryptography-protocols)\n  7. [Security Considerations](Specification.md#security-considerations)\n* [Test Vectors](Test-Vectors.md)\n  \\- This document will contain test vectors for the protocols used in the Public Key Directory.\n\n## Reference Implementation\n\nThe [**Public Key Directory Reference Implementation**](https://github.com/fedi-e2ee/pkd-server-php) is now available.\n\n## Historical Development Blogs\n\nThis section includes some highlights that may be worth considering to understand the technical underpinnings of our\ndesign. Reading them is not mandatory, but should provide insight into how we approached these problems.\n\n1. [Towards Federated Key Transparency](https://soatok.blog/2024/06/06/towards-federated-key-transparency) (June 2024)\n    * This blog post kicked this project off. It explains the motivation and how it fits into the goal of delivering\n      \"end-to-end encryption for the Fediverse\".\n2. [Key Transparency and the Right to be Forgotten](https://soatok.blog/2024/11/21/key-transparency-and-the-right-to-be-forgotten/)\n   (November 2024)\n    * This blog post describes how we square the auditable, append-only nature of Merkle Trees with a desire to not make\n      complying with a nation's *Right To Be Forgotten* technically impossible.\n\n## Extensions for Auxiliary Data\n\nSee the [Extensions](https://github.com/fedi-e2ee/fedi-pkd-extensions) repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffedi-e2ee%2Fpublic-key-directory-specification","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffedi-e2ee%2Fpublic-key-directory-specification","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffedi-e2ee%2Fpublic-key-directory-specification/lists"}