NNS - The Name Name System

Name Name System Specification v0.0.1

Editors

Authors

Depends On

0 Abstract

The Name Name System is a decentralized system for the storage and retrieval of mappings between verified names.

1 Introduction

If you never say your name out loud to anyone
They can never ever call you by it

  • Regina Spektor, Better

1.1 Motivation

1.1.1 People need names.

People need names. Moreover, they have a fundamental right to a name, according to the UN Convention on the Rights of the Child. Having a name ensures our identity and individuality.

Names are the primary instrument with which we navigate the social world. Imagine, for a moment, what not having a name would entail; we wouldn’t be able to speak of our friends, family, or colleagues. Our ability to find people, even in extremely small social sitautions would be decimated. We’d have to resort to describing people: “the friendly one, who works at the bakery”, and hoping that enough context was present to convey our meaning. Of course, with enough specificity, “the friendly one, who works at the bakery” becomes a name; Amit Baker, for example. Even without names, names emerge.

Without names, we’re dehumanized, literally stripped of our identity. We become numbers: prisoners, without context and identified only in a way that is controlled by our captors. It’s not enough to have a name; it’s essential to our humanity that we have names that we control. If someone else can change our name, then they can change us: who we are, at a relational level, is defined by our names.

1.1.2 People need names that work in online spaces.

Online, we lack the context of the real world, which means that we need to have names that carry some context. These can be petnames, names that we store in our own local address books, or names like email addresses that rely on a globally agreed and negotiated namespace (in the case of email, that namespace is the IANA-managed DNS system).

The challenge with these namespaces is that we become bound to them; an email address at gmail.com becomes a person’s primary identifier across a whole range of internet services, but is “owned” by Google, not the individual. The approach in this specification seeks to provide an infrastructure that addresses all of the issues above, and restores agency to users whose names have been established in the context of enclosed corporate spaces.

All of the above needs to account for the fact that many people have multiple names, especially in online spaces. In real life, people change their legal name, they might go by a nickname, titles often stand in as names for one or more people (“I’d like to speak to the manager”). Online, we tend to have one name per account; an email address, a different name on each social network we join, a name per work chat or document management context. Any system that deals with names online in a credible way must allow users to attest and understand the relationships between different names.

In the opposite direction, people have names and social contexts that they keep separate from eachother for very specific and intentional reasons. It should not be necessary for an individual to create linkages between all their names, or for an individual to disclose any of their names.

1.1.3 Things need names, too.

While not a question of human rights, we give things names, too.

Many of the challenges expressed above relating to people’s names apply to names we hold for inanimate things, as well.

It would be ideal if a global naming system could support these kinds of names, too. Some examples are domain names and host names, ISBNs, software package names, and far too many others to list here.

1.1.4 Computers need keys.

While people need names, for secure operation, software requires cryptographic keys in order to positively identify actors in a system, and to correlate those actors across sessions. Historically, those keys take the form of passwords, but in decentralized contexts where even secured hashes of passwords cannot be shared, we need tools like asymmetric cryptography in order to provide this functionality.

It is important for any software system that bridges a usable “human name” and a machine-oriented name or key to be able to transition securely between the two names; for example, from an email address to a public key.

1.1.5 Legacy systems need support.

The internet is built on a rich foundation of standards, many of which predate modern cryptographic tooling. Given a system that maps between names, it should be a goal to support non-human identifiers on both sides of the mapping. In particular, many existing naming systems do not transfer easily to a permissionless, offline, or peer-to-peer environment and would benefit from a naming approach that allows us to bridge that gap.

1.2 Non-Goals

While this specification strives for completeness, there are a number of use-cases that we don’t seek to support here.

1.2.1 Push or Peer-to-Peer Gossip Systems

NNS is designed as a lookup system. As such, it seeks to describe a mechanism to quickly go from a known name within a namespace to a key and published data about that name. Many systems may find it preferable to rely on names discovered by other means, including “gossip” protocols or other push mechanisms.

While it is entirely possible for WhoCANs to be transmitted directly from one peer to another, or distributed via a push mechanism, this specification does not attempt to describe any mechanisms to do so, beyond those necessary to support the functioning of a service-oriented network.

1.2.2 Global Consistency of Name Resolution

While NNS’s design intends to provide an eventually consistent view of the world, it is likely impossible to do so perfectly and in a way that is acceptable to all uses and namespaces. Instead, if global consistency is required for a given name-to-key or name-to-data mapping, an external mechanism should be used.

1.3 Examples

The following are some potential examples of things that could be built with NNS.

n.b. that these have wildly varying degrees of difficulty, and inclusion here is not intended to imply that the example should be implemented, only that it could be.

  • Pointing from a name in one namespace (e.g., dns/email) to another (e.g. a petname, or a name within a pet-namespace)
  • Mapping from an email address to a public key
  • Mapping from an email address to profile information (e.g., ActivityPub endpoint)
  • Mapping from a phone number to an email address
  • Mapping from a domain name to an WNFS path.
  • Mapping from one postal address to another, or an email address to a postal address
  • Pointing from an HTTPS URL to an IPFS-hosted version of same without Signed HTTP Exchange
  • Securely providing DNS records with low latency.

1.4. Requirements

1.4.1 Permissionless

Anyone should be able to add a name to the system provided that:

  • The name is verifiable
  • The name is verified

It should be possible to host a name for which one doesn’t control the authority (i.e., anyone in the network can host/mirror/provide any subset of names)

1.4.2 Delegatable Management

It should be possible to either (1) self-host a name or (2) pay someone
to host a name on your behalf.

1.4.3 Performance

DNS-level performance is probably “good enough”; Google reports 300-400 ms real
average latency (accounting for failed responses), 130 ms for servers that
respond.

A target of sub-100 ms latency over the public internet for uncached reads seems like a reasonable goal, because why not try to do better than DNS?

For writes, high performance isn’t critical. Individual WhoCANs can define consistency guarantees at the level of verification, but e.g. DNS as-is doesn’t provide any information about write speed, as there is no common interface for writing names into DNS.

1.4.4 Scalability

The system should work in online and offline contexts, or within a partitioned network. The operational complexity of the system should remain constant regardless of the scale of the deployed system. Similarly, the performance characteristics should be constrained only by the inherent latency of the network it’s running on (speed of light and all that).

1.4.5 Resilience

The system should be resilient against known malicious attacks (see: Security Considerations).

While byzantine fault tolerance is an ideal goal, global consistency is considered unnecessary for the system, since there are opportunities within the WhoCAN system to account for inconsistency at the network layer.

However, the network is designed in such a way as to provide reliable and eventually-consistent reads within a short timeframe after new writes. The network should be monitored for overall consistency, especially the latency necessary to attain a consistent state after writes, and adjusted as necessary to provide an acceptable level of service.

1.4.6 Backwards Compatibility

A system that’s backwards-compatible with existing name lookup systems,
where one exists for the namespace.

2. NNS Protocol

2.1 API Methods

The API methods below are exposed as HTTPS endpoints. See [NNS.dht] for the method to discover and navigate endpoints.

n.b. that all requests MUST be made over HTTPS, but the security of the system does not depend on HTTPS validation of the HTTPS certificate.

2.1.1 POST /set

2.1.1.1 Arguments

Arguments are provided using an application/json-encoded body.

!!! NOTE: should this be CBOR encoded, or other?

name: A name.
value: A WhoCAN, verifiable by the network.

2.1.1.2 Authorization

Requests MAY optionally include an Authorization header, which may be desirable to prevent nodes from handling large volumes of invalid anonymous set requests. Nodes SHOULD use UCAN bearer tokens to authenticate users, as described in (link to appropriate spec).

The method for establishing access to a node (e.g., payment) is out of scope for this specification.

2.1.1.3 Processing

An NNS node accepting a request such as the one above MUST validate the WhoCAN before accepting it. In order to do this, the node MUST support the did method used in the iss field.

The method used to validate the WhoCAN and establish the validity of the delegation is describe in WhoCAN, and the normative text for the appropriate did method. A longer treatment of verification for the purposes of NNS is included below in S2.x

After validating the request, the node SHOULD propagate the name via the mechanism described in 2.2, NNS.dht.

(aside: the long-term expectation is that validation can be outsourced to a trusted wasm blob; a parent one for WhoCANs, and sub-delegates for verifying did methods. Pointers to these methods could be stored in an NNS namespace; e.g. “wasmpkg:code.fission.codes/whocan:verify” and “wasmpkg:code.fission.codes/did:mailto:verify”) to ensure the ability to upgrade code in future.

2.1.1.4 Response

The response code MUST be one of:

  • 201 Created, if the request was successfully validated and stored.
  • 202 Accepted, if the request was valid but the WhoCAN was not validated before the node returns an HTTP response.
  • 400 Bad Request, in case of a malformed request or invalid WhoCAN
  • 401 Unauthorized, if the request is does not have an acceptable Authorization (per 2.1.1.4)
  • 409 Conflict, if the WhoCAN is valid but is inconsistent with prior WhoCANs (out of scope for this specification)
  • 429 Too Many Requests, if the request is rate-limited.
  • Any valid HTTP 500 response in the event of a server error.

The response body SHOULD provide descriptive information regarding the status of the request.

2.1.1.5 Example
POST /set HTTP/1.1
Host: nns-node.net
Authorization: Bearer {token}
Content-Type: application/json

{
    "name": "alice@example.com",
    "value": "{
                iss: "did:mailto:alice@web.mail",
                aud: "did:key:zAgent",
                att: [{ can: "ucan/sign", with: "*" }],
                prf: [{ DKIM Proof }],
                fct: [{ "profile": "ipfs://$CID" }]
                exp: future,
                sig: "..."
              }"
}
2.1.2.6 Privacy Considerations

It is not possible to both verify the WhoCAN and maintain privacy of the name. Names shared on the NNS network will be readable by any peer systems.

It is, however, possible to host names on the DHT without disclosing names to other nodes (see GET method 2.1.2.1), with the caveat that these names will not be replicated by other nodes, which may have an impact on latency to resolve these names.

It may be possible to verify WhoCAN names using homomorphic encryption in the future, in which case names could be shared in a fully encrypted form (with the name as the encryption key, and the name shared as a hash of the name). Alternatively, a scheme involving trusted notaries could be adopted; however, that is out of scope for this document.

2.1.2 GET /{name}

2.1.2.1 Arguments

The name argument is the only argument.

!!! NOTE: This should be two arguments: the hash of the name, not the name itself, and some routing hints, since the node doesn’t necessarily know the name, and in order for the DHT to be performant, we need hierarchical routing. I’ve left this as just name for now for clarity, but please assume that the request is intended to preserve query privacy.

2.1.1.2 Authorization

Requests MAY optionally include an Authorization header, which may be desirable to prevent nodes from handling large volumes of anonymous get requests. Nodes SHOULD use UCAN bearer tokens to authenticate users, as described in (link to appropriate spec).

The method for establishing access to a node (e.g., payment) is out of scope for this specification.

2.1.2.2 Response
2.1.2.2.1 Successful Response

If the server has value(s) for the requested name, the response MUST be a {encoding}-encoded encrypted JSON (CBOR?) list of the original WhoCAN(s) as submitted to the network. The response MUST also include a corresponding list of notarizing assertions, signed by the node’s public key in UCAN format, attesting that the node validated the WhoCAN(s) provided in the response.

(note that the server can pre-compute the attestations and store them alongside the WhoCANs; the expectation is that returning these attestations at GET time adds negligible overhead, and provides the ability to censure servers that provide invalid responses)

The payload MUST be encrypted using (x) with a symmetric key that is the original, un-hashed value of the name.

2.1.2.2.2 Indeterminate Response

If the server does not have value(s) fro the requested name, it can choose one of two options: it MAY act as a proxy, and traverse the DHT to find and return the response for the client, or it MAY return an appropriate 3xx HTTP response to direct the client to a different node that might have more information about the name.

2.1.2.2.3 Cached Response

In the event that the client provided valid HTTP cache headers, the server MAY respond with an HTTP 304 response, indicating that the name is not modified, and omit the response body.

2.1.2.2.4 Error Response

In the event of a server error or malformed GET request, the server SHOULD respond with a valid HTTP 4xx or 5xx response code. In either case, the format of the body is undefined, but should provide useful debugging information where possible.

2.1.3 Intentionally not included: /revoke

A revoke method for names has not been defined, since calling set in a way that invalidates old WhoCANs is probably better than a dedicated revoke method, because revoke is less likely to be consistent.

!!! Note: this may be a mistake. Thoughts welcomed!

2.2. NNS.dht

!!!
nb. this section is a work in progress and makes unsubstantiated claims; proceed with skepticism and caution. Feedback or thoughts on how to improve the DHT proposal are extremely welcome.
!!!

Due to the latency and verification requirements of the NNS system, there is no acceptable off-the-shelf DHT. However, many of the desired properties can be achieved with relatively minor tweaks to existing approaches.

  • Kademlia-based, but maybe it should be MDHT or similar?
  • Prefix bloom filter
  • nodeid: [support] [prefix] [nodeid]
  • Nodes MUST set the bits for resolution protocols they support in the
    “support” section of the bloom filter/node id in order to avoid routing
    requests for storage/retrieval to nodes that do not support that scheme.
  • Nodes SHOULD set the bits for the prefix they wish to host in the
    “prefix” section of the bloom filter/node id in order to decrease routing
    path distance.
  • Key hash encoding:
    • calculate hash of key (e.g., did:mailto:blaine@fission.codes)
    • prefix with:
      • a bloom filter including the verification method of the key (did:mailto)
      • plus prefix of address added to a similar bloom filter (codes.fission)
  • perform normal kademlia routing, with optional cached routes to nodes that match
    • first the support filter
    • then the prefix filter

2.2.1. Name Sharing / Distribution

2.2.2. Routing

2.2.3. Bootstrapping

2.2.x. ???

What else am I missing here?

2.2.x Caching

Edge nodes SHOULD provide a caching layer to prevent repeated queries to the wider DHT. Nodes MUST obey TTL information on the WhoCANs (if present) and remove any expired names from their cache.

2.2.x Updates

Due to the complexity of implementing push updates across a very large network in an efficient way, this specification does not include a gossip protocol approach to sharing updates. However, it may be advantageous for certain use-cases to enable push updates to listeners. There are a number of viable approaches, such as EBT, but this functionality would warrant further research (and may be unnecessary if the real-world latency and scalability of the DHT protocol are acceptable).

2.4. Validation

  • The payload must be a verifiable delegation UCAN (WhoCAN) that delegates
    a name to a did:key and an optional URL.
  • The content at the optional URL should be in (provisionally) webfinger
    profile format.
  • For privacy, it should be possible for a node to host a name that is not public, and whose data is not intended to be public. In order to do this, the node can require authentication on Get() requests (in the form of a UCAN) or provide the response for a name as an encrypted bundle. In this case, the name will not be stored by peers since it is not verifiable (barring advances in homomorphic encryption or in the case of names whose governing authority has signed the encrypted WhoCAN in a wrapping WhoCAN).

3. Terminology

3.1 Name

A name is any unicode string that has a corresponding DID method (i.e., there is a way to verify ownership of the DID)

3.2 WhoCAN

A WhoCAN is a UCAN that delegates from one did to another. Compare with Verifiable Credentials.

4. Security Considerations

4.1 Privacy Considerations

4.1.1 Enumeration of the Keyspace

The names stored in NNS must not be trivially enumerable. Obviously, if someone already has the name, they should be able to query for it, but building indexes of names shouldn’t be possible by scanning NNS itself. Preventing the enumeration of names using mechanisms unrelated to NNS is outside the scope of this document.

4.1.2 Encrypted Data

It should be possible to support encrypted or local-only storage of WhoCANs in order to support names that are not publicly disclosed.

4.2 Verification of Names

While the nodes MUST validate the WhoCANs that they store, clients must also verify the WhoCANs (or delegate to nodes that they trust to do the verification for them). The protocol design mitigates against malicious or defective nodes by using local consensus measures in order to ensure good performance and reliability across the network, but cannot wholly prevent unverified data being introduced.

4.3 Hijacking Names

This is a thing that would be bad.

4.4 Denial-of-Service Attacks

4.4.1 DHT flooding attacks

Creating many nodes with intentionally malicious behaviour in order to prevent legitimate nodes from providing responses to queries.

4.4.2 DDOS attacks

Attacks created by large numbers of outside actors sending large numbers of spurious requests to the network in order to overwhelm the nodes in the system. Possible by flooding with either Get() requests or Set() requests (even with invalid records). Probably necessary to provide mitigations.

4.5 Malformed Input Attacks

Attacks as a result of using malformed input, either in Get() or Set() methods that causes errors or exploits in the nodes.

5. Related Work and Prior Art

5.1 Prior Art

5.1.1 DNS

DNS is great, but doesn’t handle anything that isn’t a domain name, has a single point of authority (not a bad thing! Just not great for every use case), and doesn’t have a permissionless way to do scoped/local names (i.e., setting up an intranet DNS server requires a lot of coordination).

5.1.2 GNS: GNU Name System

Pretty complicated, only does domains. Positioned as a replacement for DNS servers, not much else.

5.1.3 Webfinger

depended on adoption by incumbents with no motivation to support (or, worse, motivation not to support). Goals were well understood by a core set of contributors, poorly communicated.

5.1.4 Webfist

Very similar to Webfinger’s approach, iteration on Webfinger; built as a hack day project, was never iterated on. Terrible name. :joy:

5.1.5 did:orb and sidetree

Not dissimilar to NNS’s goals, but does not provide a globally uniform lookup mechanism.

5.1.6 IPNS

5.1.7 DNSLink

5.1.8 PGP WoT / Open Rings

Assumed email insecure, bootstrap via incredibly complicated social ritual, extremely high cost associated with losing key. Also: slow, poor tooling. Vastly too early. Discovery

5.1.9 XRI

Profiteering. Centralized. Schema-focused (XML dayze) vs action.

5.1.10 Keybase

centralized, bootstrapped identity from centralized systems – no path to true autonomy. Sold out.

5.1.11 ENS

Parallel system to DNS, fundamentally focused on monetizing names (see also XRI), with a crypto lens so theoretically decentralized, but fundamentally too expensive with no credible story for reducing costs. Significant community issues especially with regards to trust and safety for LGBTQIA+ individuals and the founders/DAO/token holders.

5.1.12 Keyoxide

Decentralized replacement for Keybase. Uses archaic PGP keys, no global/decentralized name lookup system. They point to the possibility, but don’t describe a mechanism.

6. Acknowledgements

  • Brooklyn Zelenka
  • Zeeshan Lakhani - DHT help
  • Bill Thompson - name
  • Mikael Rogers - http interface

7. References

7.1 Normative References

  • WhoCAN
  • UCAN
  • Kademlia
  • Webfinger Profiles

7.2 Informative References

7.2.1 DHT Research

7.1.2 Other Related Distributed Systems Research

8. FAQ

13.1 Is this a standard?

No. I don’t write standards. It’s just a thing we think is useful, and others are welcome to use it and contribute proposed improvements and code.

9. Annexe

9.1 Other Widely-Deployed and Successful Global Addressing Systems

9.1.1 Postal Addressing

Global, universal, decentralized, not dependent on technology. Trust-based, but third parties provide secure/authenticated delivery. Addresses are effectively opaque to the end user (esp. across international boundaries). Finds a balance between strict naming systems (postal codes) and pseudo-petnames (e.g., letters addressed to Blaine, Slocan Lake, BC will probably find their way to me). Addresses are globally unique with sufficient (optional) specificity.

9.1.2 Phone network

Global, universal, decentralized. Standardized and not petname-based; routing network is encoded in the address. Allows for local abbreviations by omitting parent levels of routing, at the cost of added complexity (e.g., omitting +1 in North America for local numbers, or the
+44 (0) 12 345 6001 notation in Europe, which means: “omit the 0 for dialling from an international extension, omit the +44 and use the 0 prefix for dialling within the +44 country code.”)

People manage, only barely – increased international communication plus ubiquitous contact stores on phones means that memorization is no longer necessary and we default instead to full expanded form. Deeply insecure by virtue of the legacy SS7 network having no meaningful protections aside from contractual. Uneven application of standards across international boundaries (whither art thou, callerid?!)

Notably, phone number addressing has been re-used by Signal and WhatsApp, with some advantages (phone-local bootstrapping of numbers in the contacts db) and significant disadvantages (involuntary disclosure of the existence of accounts [not necessarily a problem], inability to switch accounts/use burner accounts easily, security is fundamentally linked to telco security (lol) and I don’t care what anyone says about that because key rotation warnings will always be ignored)

9.1.3 DNS

9.1.4 Email

Global, universal, decentralized, standardized. Main issue is that identities are not secure except as validated by domain owner (“reset password link” or OIDC). Primary identifier in use by virtually every online system. Significant identity lock-in, few motivations for providers (Google, Microsoft, Yahoo, AOL, Universities, Apple in that order *pull stats) to build decentralized alternatives. Increasing spam mitigation means it’s increasingly difficult to self-host, diminishing decentralization afforded by DNS. Probably a lot more to say here.

9.1.5 Centralized Global Systems (Monopolies)

Twitter/Facebook/Instagram/TikTok

Centralized identifiers, notarized by large corporations. Twitter/instagram/tiktok primarily “username” based, allows for multiple identities. Globally unique, within a single namespace. Significant first-mover advantage to naming. Content-based discovery of identities, depends on publicity (i.e., not good for private accounts); this applies doubly-so for Facebook. No credible path to decentralization aside from adopting DNS-style scheme (e.g., blaine@twitter.com)

9.2 Petnames

Aside: petnames. Very useful for local-first/personal systems where bootstrapping the network can happen in-person / via direct device-to-device negotiation. Not useful for async/remote bootstrapping of networks.

Christine Lemmer-Webber’s writeup on petnames is extremely relevant here. In the context of that paper, NNS can be understood as an “Edge Name” lookup registry. Any edge name that is able to verify a name within its “petnamespace” can be included in the NNS system.

10. Open Questions

Population Protocols

Once we have the DHT, how do we create local swarms so that servers that have opted in to serve names are guaranteed to be given the opportunity if no-one else can do it?

Notarization

This is more a question for WhoCAN, but notarization is likely to be an important aspect of all this.

Responses

Should the responses be signed?

8 Likes

:clap::clap::clap: YAY posting early and often! :tada:

2 Likes

Amazing :laughing: :clap:

2 Likes

I am happy to say that I understood and could follow perhaps 50% of this!

“… in this space …” ← which space? Is the statement still true with this clause removed?

Verified Credentials → Verifiable Credentials

1 Like

Q.E.D.

Very excited to see an alternative to DNS :tada:

Personally I’d like to see how Webnative would work with something like this. Mainly to replace DNS (filesystem root CID pointer & pointers to DIDs), but also what the effect would be on the username system we currently have.

I guess I’m mostly confused about what WhoCAN actually is.
The terminology section explains it as:

a UCAN that delegates from one did to another

But isn’t that always the case for UCANs? iss delegates to aud?
I was also looking at https://talk.fission.codes/t/whocan/3517
But that seems like it’s a premise to NNS? Or did I misinterpret?

That pretty much ties into my next question, can I use NNS directly in the browser without having another server in between? To be more specific, take the example of how we do a data root update in Webnative (ie. update the filesystem-root-CID pointer). The Fission server validates/verifies the UCAN sent from the client and only then updates the DNS pointer. Can we do that with purely Webnative + NNS? Would we map webnative:data-root:DID_GOES_HERE to pointer?

Not sure what the role of this is.

Bit confused of the symmetric key aspect, since this is the only place it’s mentioned. How would one decrypt this content?

How do you see the different NNS systems interacting? Would NNS systems be hosted in a community-like manner? Or is it running client-side with P2P, if not, how do you see it scale?

I’ve got a lot of preamble, and hopefully it’s useful, but maybe it needs to go elsewhere?

Definitely liked the preamble, feels right to have it in there.

I think there’s potential application of NNS to WNFS hosting, auth lobby/Webnative Auth/sign-in systems in general, …

Would love to get your perspective on WNFS hosting + sign-in systems. What would you change in the current architecture of Webnative? Or put differently, how do you see WNFS hosting and sign-in systems working with NNS? (I guess this is very similar to my second question with the data root example, so feel free to skip)

Amazing, thanks so much :pray: I’ll reply to the various bits individually.

1 Like

:100: I haven’t interrupted that work with these ideas because I haven’t seen anything that would be incompatible, but it’s definitely a hope / goal that we can tie NNS into Webnative and improve our DNS links and sign-in usability!

This is a really good set of related questions. I’m not sure if I can explain it well, but hopefully I’ll arrive at something clearer through trying!

So! Yes! It’s absolutely possible to use NNS just in the browser, or probably more usefully, in a local-first context (using NNS in the browser would be a bit overkill, since the purpose of NNS is to do lookups; if you’re in a fully local context, you don’t need a DHT to do that). More properly, I’d say that it’s possible to use WhoCANs in the browser, and to obtain them via e.g. gossip methods. I haven’t tried to describe the gossip approach since that’s a whole separate thing, but definitely worth noting that it’s possible. NNS is just a lookup mechanism for WhoCANs.

As to what a WhoCAN is vs a UCAN, per my understanding, the only difference is that a “WhoCAN” contains a proof of ownership of a did that can’t be intrinsically proven. That’s what the DKIM proof is - basically, I send an email with my DID in the subject line that’s signed by some keys that are discoverable by DNS or some other mechanism (maybe ACME, etc), and include that email in the UCAN. You’ll still need to go fetch the DKIM keys to verify ownership (probably via a Certificate Transparency mechanism), but now I can say I control “blaine@fission.codes” and I want to delegate it to this did.

I think there’s a good chance you’re right, and the verification is intrinsic to the did method, so assuming that the UCAN spec provides for verification of non did:key dids, then NNS can work with any UCAN.

There’s a slightly orthogonal question that gets at this question of “what is a name” that I was trying to tease out of re: “computers need keys” vs “humans need names.” The idea with a WhoCAN is that it’s mapping from a “human readable” name (email address, domain name, fs path, http uri, etc) to a key – there may be multiple layers of indirection, but ultimately the goal is to get us to a key in order to take advantage of capability-based security, etc.

I’ll stop there – hopefully that makes sense, but if not, please lmk! I’m not wedded to the WhoCAN thing, but I do think it’s important to emphasize that it’s not just for key-to-key mapping.

This overall aspect of the spec needs to be clear and understandable, and @cdata was asking similar questions, so it definitely needs work.

3 Likes

The key is just the name, but you need the name in order to retrieve it. This is just to prevent casual inspection of the payload; the get request uses the hash of the name, not the name itself, so neither passive nor active MITM attackers wouldn’t be able to determine the original name, so long as the payload is encrypted.

I suspect there will be a few different modes; the most common will be service providers joining the dht and providing guaranteed availability of names on behalf of users, for a fee (probably bundled with other services). An example would be for our filesystem root CID pointers, we’d just run a service that guarantees their availability.

The next most common will likely be private NNS networks. Something along the lines of MagicDNS, but self-managed.

The final mode would be just a community p2p network, where people participate in hosting the network. Part of the first mode would include this, and we could obviously do something like filecoin to incentivize doing so, but I’m not sure it’s worth the effort, at least to start.

I think there are a bunch of possibilities here! One of the first would be the ability to tie e.g. an email address to a passkey, so that e.g., if the user doesn’t have their passkey UCAN available, we have clear fallback mode(s) available to offer them. Similarly, we could encode the user’s preference for sign-in method in their UCAN, make that available via NNS, and then respect that preference going forward whether or not we have a cookie - just ask for their username, and away you go!

As you suggested, one of the other main use-cases would be storing the fs root CID pointer in NNS. We could also extend DNS in a way that’s (1) secure and (2) supports independently manageable “zone files” for subdomains. The proposal that Irakli had around this was basically putting a delegation key into the top-level DNS entry for a domain (so, signed by DNSSEC) and just using that to verify signatures at the WhoCAN/NNS level.

Another use case that came up (@Quinn’s proposal) was to use NNS as a way to point from an HTTPS endpoint (e.g., “https://example.com/content”) that’s expensive to host to a CDN that doesn’t have domain control. e.g. an IPFS CID. Obviously, it’s really hard in practice to sign content with Signed HTTP Exchanges, so few know the functionality exists, let alone can implement it. With NNS, all you’d need to do is issue the equivalent of an HTTP “See Also”, sign it with a key that your HTTP server can attest to (e.g., by using ACME, the method that Let’s Encrypt uses to issue keys or similar (I haven’t done the legwork to see if ACME specifically would work, but I can imagine other simple methods to do similar)), and then post it to NNS. Now, anyone who uses NNS can securely fetch the other resource and know that it’s the same content (well, at least according to the server that issued the original See Also record).

1 Like

Ok. I’m trying to think through stuff that this enables. Please bear with me as I output my stream of consciousness:

did:mailto:did:key: “ownership” delegations seem like nothing new. You could root all your UCANs in an eventual did:mailto:s which use signing via DKIM.

However, this has the DHT/lookup protocol attached to it, so I don’t necessarily need to have such a rooted UCAN in advance.

E.g. if I want to share some WNFS file with a friend of mine, and I know their email address is blaine@example.com, I could ask the NNS and would get back Blaine’s DID! So now I can … use that DID to look up the file system root in… IPNS/w3name I guess? Or at some other service that I know Blaine uses to manage WNFS root pointers?
Should a WNFS be rooted in NNS directly? I don’t think so, as that’d mean it needs to be frequently and low-latency update-able.

Also I see that responses are non-unique, which makes sense since there’s nothing preventing someone from uploading multiple WhoCANs for a name. But that means as a recipient I have to choose somehow :thinking: Perhaps it’s possible to build protocols on top which make choosing a unique “most recent” WhoCAN possible (eventually).


I’m still trying to wrap my head around what this is doing :slight_smile: Is this essentially a bridging system between naming systems? It’s not like anyone can attest for any name, it must be names which users can “prove” access to already. So E.g. email with DKIM, or ethereum addresses. Am I thinking about this correctly?

This is great work! I’ve been working with Subconscious folks on the Noosphere NS (spec, source), a DHT network for mapping identities (public keys) to its most recent content address, not dissimilar from IPNS. We are very interested in collaborating on a shared name system for decentralized identities, hoping our use cases align, and extending our NS beyond Noosphere.

To clarify, is there any restrictions on what may be the KEY and VALUE, in DHT parlance? Or general purpose authorized mappings? For background, the Noosphere use case is specifically did:key to CID (of a UCAN containing a fact with a CID address to the corresponding key’s latest content).

I’m not terribly familiar with WhoCAN, but is a WhoCAN required for participating in the NNS? If a WhoCAN resolves to a did:key, can it resolve a did:key to an address? My understanding is that WhoCAN is still being fleshed out, any good resources here? Is it required for NNS to be coupled to WhoCAN? Perhaps nodes could identify what key types they support as well to be more key agnostic.

Also, is it out of scope to have authorized, but unverified (what we use, e.g. did key, no WhoCAN) identities in the network?

While the Noosphere gateway runs both an HTTP server and a DHT NS node, the NS isn’t exposed over HTTP. Is there a 1:1 relationship between HTTP servers and DHT nodes here? Is it required for NNS participant nodes to also have an HTTP interface? This seems like it might be a bonus/optional layer, or a service that interacts with the underlying DHT – that is to say the benefits of collaborating over a DHT API (compatible nodes strengthening networks) is more immediately valuable to us than a compatible HTTP interface.

(Continuing in new post due to 2 link limit)

Some prior art here in Noosphere Name System, which is mostly libp2p’s Kademlia DHT Spec with some specificity on using UCAN as NS records, and future work evaluating verifiably “most recent address”, settling on value vs provider records, and other improvements upon the v1.

I think the DHT spec here could mostly leverage the Noosphere/libp2p work here, layering on some UCANisms.

Note that using libp2p leaks some implementation details into the spec, like using Multiaddr for bootstrap address.

Is this restriction a property of the HTTP API only? Due to the nature of DHTs, are there any common solutions for obscuring keys hosted on nodes?


We’re still iterating over our NS design, and the NNS spec has given me a lot of food for thought! I hope we can collaborate more here and build a network that works for all of us.

Almost! One of my main goals here is to support pointing at the FS root directly in the NNS record. My current hunch is that we could use a fct with the FS root CID directly in the record that gets returned for blaine@example.com (DKIM-signed and delegates to the did:key that is responsible for the FS root). So, no IPNS required. We could do this with indirection, as well, but I would err on the side of keeping things simple until we have a better understanding of the trade-offs.

The goal is very much to support high-frequency and low-latency updates, and have retrieval be extremely low-latency. I’ve done some math & research and I think this should be possible as long as the names have a hierarchical component.

The long form: because the latency of DHTs is so network-bound, and each hop is bounded by c, reducing retrieval to sub-logarithmic can have a huge impact on actual latency. Uniformly distributed keys (e.g., with CIDs) can’t do better than logarithmic without massively increasing the number of keys pinned by each node, which has a negative impact on costs and consistency. By taking advantage of the fact that virtually all names that we care about have a hierarchical component, we can do better than default kad routing, but using most of the same semantics as kad.

My untested hypothesis is that we can actually do better than DNS on median lookup latency, even with a keyspace that’s many orders of magnitude bigger and without needing archaic and bespoke approaches to updating records; just a universal set method.

Yes, that’s right. At first I had a giant rollup HAMT/prolly tree construction (:notes: It’s beginning to look a lot like block·chain :notes:) to provide consistency “guarantees”, but @expede convinced me that leaving that at the name level is probably better. There are so many ways to approach that problem, and baking in anything more complicated than a timestamp probably isn’t worth the complexity.

Yup!

It started with email-with-DKIM, but I switched to a more generic approach when it became apparent that we could also do this for DNS, HTTPS URIs, ETH addresses, etc – anything that can be verified. The extremely short form is “decentralized keybase with a fast lookup method.”

UCAN+verification methods for dids including but not limited to did:key => “WhoCAN” == “decentralized keybase without storage/lookup”
NNS == fast decentralized storage/lookup for above.

1 Like

Excellent work! Super excited about this! :sparkles:

Steven and Philipp have asked many of the questions I had around how this could work with Webnative and WNFS.

I do have a question about revocation.

My understanding is that set can be used to update a the WhoCAN associated with a name. Can it also be used to delete a name from NNS? Is it useful to be able to delete a name or should names only be updated?

Thanks for being patient @blaine, I’m just getting around to this in detail now :eyes:

The TL;DR is that this matches the picture in my head from our previous conversations and my earlier quick read of this text. I’m excited to have this in production!

It may be good to enumerate a couple of examples.

Nitpick: B should be capitalized in Byzantine.

There’s a distinction here between BFT and consistency. A BFT system can also be eventually consistent, it’s just that the possibly number of “broken” cases is minimized.

Recommendation: start this sentence for “Global consistency is unnecessary”.

I love the emphasis on reliability!

Suggestion: it may be worth tying this to the earlier text about agency (right to names).

I assume that I could (for example) additionally create a WSS API, as long as the HTTPS API is supported, ya?

If using HTTP, I would recommend JSON because it’s the de facto standard (at least for now). If you defined this in IPLD, it becomes representation agnostic, but I’m not sure that you want to do that at this layer.

Suggestion: I’ve had a lot of success using markdown tables for this. For example:

Field Type Description Required
name String A name Yes
value WhoCAN Object A WhoCAN, verifiable by the network Yes

Substantive question: is the format a k/v pair, or is it an object?

A:

{ "myname": {"some": {"whocan": ["whatever", "the field", "are"]}}

B:

{
  "name": "myname",
  "value": {"some": {"whocan": ["whatever", "the field", "are"]}}
}

THANK YOU FOR GETTING CONCRETE! This may be enough to take care of my comment above, but I’m leaving it there for posterity as a “hot take”

Is the "{ a typo?

I guess there’s two cases here:

  1. Updates replace (and thus invalidate) old values
  2. Forcing a revoked value to be dropped no matter what (e.g. null)

My questions are about the shape of the value field:

  • How would I unset a name? Are values nullable?
  • Can I set more than value name for a name?
    • For example: “here’s my set of (recursive NNS) names, and I may add more later”, or would that have to be a terminal node?

And on this same topic…

…this implies that more than one value can be set at a time. Is this only in the case of concurrent writes, or is it possible to do intentionally

Probably the aptly named ucan-as-bearer-token! (Feedback welcome on that spec too, btw!)

Nice, I like how flexible that is :100:

I guess there’s no security concern here other than being provided out of date records (potentially maliciously). That fits into eventual consistency, but may not be monotone, and a malicious server could return records in arbitrary order. Other than trusting the server that you’re requesting from, is there an ordering mechanism like an update counter / hash history? I’m guessing that not all names have authoritative name servers, due to wanting users to be their own authorities.

Personally I’d start with Kademlia because it’s well studied, but @zeeshan.lakhani probably has opinions [update: he’s in the acknowledgements for this, so I guess you’ve already talked!]

If I accidentally set a TTL to 100 years, do I have any recourse? This may be a good use case for a revoke or other forced update message

That’s really elegant! :clap:

It’s very hard for me to make sense of this spec without the spec to which it depends on and refers to a lot.

Is it possible to link to WhoCAN? If not, can you remove the dependency and inline what that means in here?

Same thing with did:mailto. The only thing I can find that that might refer to is a placeholder. GitHub - ucan-wg/ucan-mailto: UCAN did:mailto delegation specification

It seems inevitable that mistakes or oversights will happen if we specify the depender before the dependencies… I’m not advocating for specifying those dependencies first so much as removing them alltogether (e.g. inline WhoCAN, only refer to did methods with complete specs)

what is the syntax of name? I can’t tell if it must be of form a@b or if b is allowed, or if the syntax is more complicated.

If name can be e.g. foo, how should it be verified?

If name can be e.g. bengo.is, how should it be verified? I can think of at least two ways, which might conflict:

  • look up signing keys by resolving did:dns:bengo.is
  • look up signing keys bey resolving did:web:bengo.is