12 - Dash Platform Name Service#
DIP: 0012 Title: Dash Platform Name Service Author(s): Ivan Shumkov, Anton Suprunchuk Special-Thanks: Andy Freer, cloudwheels, thephez Comments-Summary: No comments yet. Status: Proposed Type: Standard Created: 2020-09-15 License: MIT License Requires: 11
Table of Contents#
Abstract#
This DIP outlines the initial name service for Dash Platform. After deployment and activation, Dash users will be able to register a username in the Dash ecosystem. Thanks to Dash Platform, this username can be quickly cryptographically proved to be in consensus even on non-full nodes. This name will serve as the basis for DashPay’s username-based functionalities (e.g., contact list, user-friendly transactions), which at their root involve looking up a blockchain identity by an associated name. This service is then made available to be integrated in applications whether they are developed for the Dash Platform, another dApp platform, or even a non-dApp platform.
Note: This DIP covers details specific to the design of the Dash Platform Name Service (DPNS). For background information on general Dash Platform concepts, please refer to the Dash Platform documentation.
Motivation#
As the design and development of the Dash Platform matured, potential use cases and solutions for names were considered. During this process, it became apparent that names would be helpful for referencing more types of entities than just individual users. One other example would be to enable developers to name their applications. In the future, Platform developers may develop their own use cases that will leverage the names and identities capabilities.
Requirements#
Names must be provably unique and universal in their context across the Platform.
The name format should be domain compliant.
Subdomains should be supported.
The name should be able to resolve many services for one name: identity, Keybase address, IP, mail, etc.
The system should be compatible with DNS in order to implement such functionality as:
Open a DashPay user profile by name via a URL
Open a dApp by name via a URL
When designing a naming solution, a number of attack vectors must be considered also. The solution should not be susceptible to the following attacks:
Man-in-the-middle attacks (name interception) - when a user publishes a name registration transaction to the network, someone spots it (with an automated script) and tries to register the same name so they can later resell it to the original user
Homoglyph attacks - when similar looking characters are used to create a name that appears similar or identical to another (e.g., a malicious actor substituting a Latin “a” (Unicode U+0061) for a Cyrillic “a” (Unicode U+0430) in the username “alice” in order to spoof that username)
Cybersquatting - when high profile names are registered in bulk with intent to profit off the individual or business being targeted (e.g., cryptocurrency exchange or trademarked brand)
Prior work and existing solutions#
-
Domain compliant solution separated from identities
Allows subdomains
Has a DNS gateway
Can be used to resolve many types of services
Domain owner defines pricing, TTL and reserved name strategy for subdomains
Auction system for purchasing names to prevent cybersquatting
BNS: Blockstack naming solution
Domain compliant solution separated from identities
Features transfer, update, revoke of names
Allows subdomains
TLD defines the price for the subdomain (determined by stored functions), includes TTL
IPNS: IPFS Naming Solution
Solution Overview#
Dash Platform must provide simple primitives as building blocks that developers can leverage for their needs. To provide a flexible architecture and simplify the design, identities and names are treated as related but separate concepts. There are numerous use-cases that require a naming service that is not bound to an identity system: application names, DNS, etc.
Implementing the naming solution as a service on Dash Platform provides a number of advantages:
Demonstrates Dash Platform capabilities: It’s possible to build many kinds of applications using Dash Platform, even one as integral to the platform as a DNS.
Creates a foundation for naming solution expansion: It becomes possible to easily extend the naming solution to work with DNS, assign names to email addresses, enable subdomain rules, etc.
Maintains core blockchain robustness: The more logic we put in Dash Core, the more likely we are to introduce vulnerabilities into the critical Layer 1 blockchain codebase.
Separates Business Logic (Layer 2) from Payments (Layer 1): Business logic retrieval will rely on a state tree for proofs instead of a summation of state transitions which allows for orders of magnitude more efficient proofs.
Makes it possible to resolve names directly from a browser via a DNS Gateway: For example, DashPay has the name “wallet” and we can resolve it as “wallet.dash” if we buy the “dash” TLD (or if the browser supports our naming service). Vendors like Mozilla and Opera have already integrated ENS and IPNS.
Makes it possible for third-party developers to have personalized profiles link: In the future, namespaces like subdomains may be enabled to allow 3rd party developers to create naming profiles for their app users, like “alice.wallet.dash” where “wallet.dash” is the app name.
The solution also solves a number of issues not addressed by DIP0005:
Solves man-in-the-middle attacks: with DIP0005, it’s possible for peers to intercept the registration transaction and register the name themselves. In the solution described in this document, this is prevented since the name registration is performed before the name is publicly revealed to the network. For the details please refer to the name registration section.
Improves UX: Names are usable almost instantly since they only require a block confirmation on the platform chain where blocks are formed within seconds.
Implementation#
Data Contract Registration and Security#
Dash Platform Name Service (DPNS) should be implemented as a data contract on Dash Platform. Since each data contract has an owner, an identity (DPNS Identity) must be established to register the data contract. The immutability of data contracts will ensure the DPNS data contract owner doesn’t have the ability to modify the contract. Furthermore, since user data must be signed by their identity private key, the DPNS data contract owner is also unable to modify the user’s name registration data.
Initially, only ECDSA keys will be supported for identities, but future updates will introduce BLS keys for data contract signing. At that point, the DPNS identity will be updated to add a BLS multisig key that can be shared among multiple stakeholders (e.g., code maintainers, Dash Trust Protectors, DCG board). This will be done to make sure that the DPNS data contract is not susceptible to a single point of failure. The ECDSA key will be disabled following the addition of the BLS multisig key for the identity that switches key types.
Top-level domain names#
Registration of the top-level names will be limited: only the identity that is the current owner of the DPNS contract will be able to create them. Initially, only one top level domain (dash
) will be registered and all other domains will be subdomains of it.
DNS Compatibility#
In order to provide compatibility with DNS and allow different behavior for different name segments, a domain compliant hierarchical structure will be used. In this structure, a parent’s name affects a child’s behavior.
Domain Record Types#
Initially, only Dash identity record types will be implemented, but DPNS is designed to be extensible enough that additional record types could be added in the future. The following list provides some examples of types that could be investigated after initial implementation:
Dash Data Contract ID
Url
Email
IP
Arbitrary data
Dash Identity Record#
Dash identity records establish the link between an identity and a specific name. There are two types of records that can be used to link a Dash Identity to a name:
dashUniqueIdentityId - establishes the primary name for an identity
dashAliasIdentityId - adds a secondary alias name for an identity
Domains with dashUniqueIdentityId
resolve as the primary (default) name for an identity and always have a 1-to-1 relationship to the identity (i.e., each name can only have one unique identity ID and an identity ID can only be used in one dashUniqueIdentityId
record).
Domains with dashAliasIdentityId
resolve as secondary aliases to an identity that already has a dashUniqueIdentityId
record. This means that a user can’t create a domain with a dashAliasIdentityId
record unless a domain with a dashUniqueIdentityId
set to the same identity already exists. The same identity ID can be used as a dashAliasIdentityId
record to establish 0 or more aliases.
Regardless of identity record type, the value assigned to the record must always equal the identity used to create the domain. Additionally, since only one identity record can exist in a given document, a name can only be associated with one identity.
Name registration process#
The DPNS registration process occurs in 2 steps. Each of these steps revolves around 1 document type in our contract. First we have a preorder registration step and then a domain registration step. The DPNS contract therefore has two document types: preorder and domain. For the data schema of these document types, please refer to the DPNS data contract.
The preorder step (1) is needed to prevent man-in-the-middle attacks. It registers the name for the specified identity without revealing the name itself. The user hashes the name with a salt and puts the resulting hash in the preorder document. As the salt is randomly generated by the user, it’s impossible to figure out what name is being registered until the user reveals the salt.
The register step (2) can begin once the preorder document is included in the platform state tree, this occurs once the state transition creating the document is included as valid into a committed block. In this step, the preordered name is revealed and associated with a record (e.g., the user’s blockchain identity). Since the preorder salt is also provided, anyone can hash the name/salt and validate that the name being registered matches the one provided in the preorder.
Therefore, step 1 ensures that the user registers the name before anyone can see it. Then, after the preorder document is confirmed on the chain, the user reveals the actual name he has registered.
The registering blockchain identity can remove the preorder document to save space and potentially earn back credits as an optional third step.
Preorder domain document#
A user needs to create a state transition with a preorder
document. The document is defined as shown below:
{
"indices": [
{
"properties": [
{
"saltedDomainHash": "asc"
}
],
"unique": true
}
],
"properties": {
"saltedDomainHash": {
"type": "string",
"contentEncoding": "base64",
"minLength": 43,
"maxLength": 43,
"pattern": "^([A-Za-z0-9+/])*$",
"description": "Double sha-256 of the concatenation of a 32 byte random salt and a normalized domain name"
}
},
"required": [
"saltedDomainHash"
],
"additionalProperties": false,
"$comment": "Preorder documents are immutable: modification and deletion are restricted"
}
The saltedDomainHash
for the “alice.dash” domain is calculated as shown below:
sha256(sha256(salt || lowercase("alice.dash")))
Validation rules#
Preorder documents must comply with the validation rules defined in the DPNS data contract.
In addition to data contract validation rules, preorder
documents must also pass validation rules defined by the DPNS data triggers. Data triggers provide a way to define custom validation rules that are run when a particular document type is submitted to the platform. Currently they are only used by the DPNS data contract.
Data trigger rules:
Preorder document modification and deletion are not allowed
Register domain document#
After the preorder
document is confirmed the user needs to send a domain
document defined below. Note that the normalizedLabel will be deprecated in the future when case-insensitive indices support renders it extraneous.
{
"indices": [
{
"properties": [
{
"normalizedParentDomainName": "asc"
},
{
"normalizedLabel": "asc"
}
],
"unique": true
},
{
"properties": [
{
"records.dashUniqueIdentityId": "asc"
}
],
"unique": true
}
],
"properties": {
"label": {
"type": "string",
"pattern": "^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9])$",
"minLength": 3,
"maxLength": 63,
"description": "Domain label. e.g. 'Bob'."
},
"normalizedLabel": {
"type": "string",
"pattern": "^((?!-)[a-z0-9-]{0,62}[a-z0-9])$",
"maxLength": 63,
"description": "Domain label in lowercase for case-insensitive uniqueness validation. e.g. 'bob'",
"$comment": "Must be equal to the label in lowercase. This property will be deprecated due to case insensitive indices"
},
"normalizedParentDomainName": {
"type": "string",
"pattern": "^$|^((?!-)[a-z0-9-\\.]{0,189}[a-z0-9])$",
"minLength": 0,
"maxLength": 190,
"description": "A full parent domain name in lowercase for case-insensitive uniqueness validation. e.g. 'dash'",
"$comment": "Must either be equal to an existing domain or empty to create a top level domain. Only the data contract owner can create top level domains."
},
"preorderSalt": {
"type": "string",
"contentEncoding": "base64",
"minLength": 43,
"maxLength": 43,
"pattern": "^([A-Za-z0-9+/])*$",
"description": "Salt used in the preorder document"
},
"records": {
"type": "object",
"properties": {
"dashUniqueIdentityId": {
"type": "string",
"contentEncoding": "base58",
"minLength": 42,
"maxLength": 44,
"pattern": "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$",
"description": "Identity ID to be used to create the primary name the Identity",
"$comment": "Must be equal to the document owner"
},
"dashAliasIdentityId": {
"type": "string",
"contentEncoding": "base58",
"minLength": 42,
"maxLength": 44,
"pattern": "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$",
"description": "Identity ID to be used to create alias names for the Identity",
"$comment": "Must be equal to the document owner"
}
},
"$comment": "Constraint with max and min properties ensure that only one identity record is used - either a `dashUniqueIdentityId` or a `dashAliasIdentityId`",
"minProperties": 1,
"maxProperties": 1,
"additionalProperties": false
},
"subdomainRules": {
"type": "object",
"properties": {
"allowSubdomains": {
"type": "boolean",
"description": "This option defines who can create subdomains: true - anyone; false - only the domain owner",
"$comment": "Only the domain owner is allowed to create subdomains for non top-level domains"
}
},
"description": "Subdomain rules allow domain owners to define rules for subdomains",
"additionalProperties": false,
"required": ["allowSubdomains"]
}
},
"required": [
"label",
"normalizedLabel",
"normalizedParentDomainName",
"preorderSalt",
"records",
"subdomainRules"
],
"additionalProperties": false,
"$comment": "In order to register a domain you need to create a preorder. The preorder step is needed to prevent man-in-the-middle attacks. normalizedLabel + '.' + normalizedParentDomain must not be longer than 253 chars length as defined by RFC 1035. Domain documents are immutable: modification and deletion are restricted"
}
Validation rules#
Domain documents must comply with the validation rules defined in the DPNS data contract.
In addition to data contract validation rules, domain
documents must also pass validation rules defined by the DPNS data triggers.
Data trigger rules:
The full domain name (
normalizedLabel
+ ‘.’ +normalizedParentDomain
) must not be longer than “the longest readable domain”, i.e. 253 symbols as defined by RFC 1035normalizedLabel
must be lowercase and must be equal to the lowercaselabel
Parent domain (
normalizedParentDomain
) must existPreorder document must exist (be confirmed) with
saltedDomainHash = sha256(sha256((preorderSalt || normalizedLabel + "." + normalizedParentDomainName)))
dashUniqueIdentityId
ordashAliasIdentityId
must be equal to document owner IDsubdomainRules.allowSubdomains
must befalse
for non top-level domainsTop-level domains can be created only by the DPNS Identity
Domain document modification and deletion are not allowed
Name resolution and prefix search#
The following queries are used on the platform to resolve a name or search through the registered names. In DPNS, a full domain name (e.g., “alice.email.dash”) consists of two parts: the label and the parent domain name. The label refers to the leftmost portion of the full domain name (“alice”) and the parent domain name refers to the remainder of the domain name (“email.dash”).
Resolving a name#
A name can be resolved by sending a query to get a domain
document from the DPNS contract.
Where conditions:
[normalizedParentDomainName, ‘==’, normalizedParentDomainName],
[normalizedLabel, ’==’, normalizedLabel]
The normalizedParentDomainName
is the lowercase representation of the domain for the name being requested. The normalizedLabel
is the lowercase representation of the case-sensitive label (i.e., name) used in the domain document that created the name.
For example, a query for the label “Alice” located in the “dash” domain would use the following conditions:
Where conditions:
[normalizedParentDomainName, ‘==’, “dash”],
[normalizedLabel, ’==’, “alice”]
Reverse resolving#
Reverse resolving enables retrieving a name based on record (e.g., a user’s identity). This is analogous to doing a reverse DNS lookup to find the domain name associated with an IP address. For example, to retrieve the name associated with a particular identity, the query would use records.dashUniqueIdentityId
with the value set to the known identity ID.
Where conditions:
[‘records.’ + record], ‘==’, value ]
Search through names#
A name search query works similar to resolving a name, but uses the startsWith keyword along with a labelPrefix. The labelPrefix is a lowercase representation of the character(s) at the start of a label (e.g., a labelPrefix of “al” would return both “alice” and “albert”).
Where conditions:
[normalizedParentDomainName, ‘==’, normalizedParentDomainName],
[normalizedLabel, ‘startWith’, labelPrefix]
Parsing resolved domain documents#
When parsing resolved domain documents, the username is found in the label
property. The full domain name can be constructed by concatenating the normalizedLabel
and normalizedParentDomainName
field.
Domain Management#
Update and Delete#
The initial version of the name service will not have domain update and delete functionality implemented. Future updates to the service may introduce these features to further expand its flexibility.
Subdomains#
Subdomains will initially be restricted so only the owner of a name can establish subdomains. For example, a user registering “alice.dash” could also create “mail.alice.dash” as a subdomain. In the future, DPNS may expand subdomain rules to allow domain name owners to manage subdomains with more granularity. These rules could allow them to restrict subdomain registration to themselves, open it to a specific group, or to everyone. Such a future change will merit its own improvement proposal.
Name transferring#
Similar to DIP0005, the name service described in this document does not specify a trustless process for transferring names. However, as in DIP0005, the name is effectively owned by whoever has the private key associated with the identity that registered the name. Future platform updates could potentially expand the name service capabilities to add name transfer features. Such a future change would also require its own proposal and require network support.
Data Contract Document Schema#
A copy of the initial DPNS data contract document schema is available here for reference. The current version of this information can be found in the dpns-contract repository.
Copyright#
Copyright (c) 2020 Dash Core Group, Inc. Licensed under the MIT License