About my attempts of decoupling actors from the DNS system

I’m building Project: Gimli, you might’ve heard of it before (yes, it’s the same one planning E2EE over AP and federated democracy. Making a discord alternative is complicated — it has tons of features, and a lot of missing ones too). It’s an exploratory project, where I’m implementing whatever interesting Fediverse concepts I come around. I’m documenting here, as I want to have a long-form text about it, and some people don’t want to use Google docs.

The intention here is to show how Mastodon is a legacy platform, limited by backwards compatibility to itself and lackluster database design, and more importantly, to show an example of how to do better. Plus, to create interesting discussions. Please ask questions!

Identifiers

Mastodon uses URIs to identify objects, and associates one immutable URI with one object (excluding actors, that it has hacked support of multiple predefined URIs for).

Gimli’s database uses three kinds of identifiers for every object:

  • An internal UUIDv7. That one’s boring.
  • A (nullable) federated UUIDv7. I don’t know how exactly I’m gonna use it yet, but it’ll be the main identifier for most objects. I have two concepts:
    • Use did:uuid:abc123?host=example.social as an @id. Most likely ain’t gonna use it as a primary URI (see below), as it’s gonna break compatibility with literally everything.
    • Have a uuid Json property or something. Might as well use a public/private key here, though.
  • URIs, one of which is considered the primary URI, and is the one used as an @id and in Webfinger’s subject. They’re stored funnily in the Database; every Instance has one or more socket addresses (again, one of which primary) assigned to it (a port of zero signifies usage of the protocol’s default port, everywhere), and another table contains all other parts (user information, path, and scheme) with some checks to forbid HTTP in favour of HTTPS, and to make sure URIs are valid in the ACCT and HTTPS schemes. The idea is that it’s easy to dereference any URI; grab the hostname, add /.well-known/webfinger?resource=, then the entire URI again. Add some fancy rendering client-side, and no more cursed hacks (ehm ehm Mastodon constructing acct URIs from as:preferredUsername).

This variety and multi-URI-ability allow to federate with theoretically any platform. Plus, each instance can have multiple hostnames.

Basically, we removed the incredibly annoying username immutability without breaking compatibility at all; servers that only support a single URI can just handle different URIs as if they were different objects.

Note, I’m not intending on allowing multiple URIs per post. I think.

Self-storage

The database marks an instance’ source of truth as itself by having a column equal to null.

…which means we can have multiple instances have said column equal to null. Which means we can host multiple instances on the same database. And supporting multiple instances per server means we can easily support multiple databases per server (with each database managing different instances).

Keys

The server isn’t going to manage private keys. This is security hell and something I’m simply not intending to hold responsibility of.

3 Likes

A plain UUID would not be suitable for federation because it doesn’t contain enough information to verify an object. Addition of host=example.social provides that information (I can ask example.social if an object is valid), but then your identifier becomes roughly equivalent to https://example.social/did:uuid:abc123 which is not very interesting (still coupled to DNS).
Generating identifier from a secret key is a good idea - only the owner of the secret key can do it, and DNS is not involved.

3 Likes

Indeed. Making the identifier a public key is an even more interesting idea.

UUIDs are there for three reasons:

  • I added them to instances (where it makes sense, imagine acct:laxystem@did:uuid:blah (yes I know this is illegal but this is just a concept), and just added them to everything else too. Tbf, public keys make more sense here too, but less more.
  • As a remnant of a concept I had regarding federated democracy, where we need objects not to be derefencable; That is, we need objects to only be referencable by asking your trusted instances what they’re - basically, matrix rooms, except good.
  • UUIDv7s are cool and I like them, they force instances to tell you when objects were created.
  • Humans can memorize them, if they want to, for some reason.

I think I’ll now have to go do some research into protocols (especially crypto ones) to see if any of them registered a scheme for public keys. Done! did:key exists.

Update: here’s how did:key works.

  1. Prepend the did: scheme scheme, as usual for decentralized identifiers.
  2. Prepend the key: method, because we use keys.
  3. Add a letter from this table based on what encoding we use. The best available is z, which is bitcoin’s base 58.
  4. Choose your algorithm from this table, and prepend its identifier (written in hex value in the table) to a byte array containing your key. (I’m not sure about this one)
  5. Encode said byte array under the base you’ve chosen above and append it to your URI.
  6. Wallah!

And the best part, I don’t even have to worry about half of this, because it’s implemented, including for Kotlin/Multiplatform.

Thank you, crypto bros, for making web protocols for the next generation of currency that I can de-abuse for cat-pic-sharing-purposes.

1 Like

If you want to use did:key in identifiers, one possible approach is described in FEP-ef61. It introduces a new URI scheme that allows building identifiers by combining a public key (e.g. in the form of did:key) with some unique string:

ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/myobject

Then you can sign your object to make it self-contained. Example:

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/data-integrity/v1"
  ],
  "type": "Note",
  "id": "ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/myobject",
  "attributedTo": "ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/myactor",
  "content": "Hello!",
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-jcs-2022",
    "verificationMethod": "did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2#z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2",
    "proofPurpose": "assertionMethod",
    "proofValue": "..."
  }
}
1 Like