Decentralized Identifiers (DIDs)

BNS nodes are compliant with the emerging Decentralized Identity Foundation protocol specification for decentralized identifiers (DIDs).

Each name in BNS has an associated DID. The DID format for BNS is:



  • {address} is an on-chain public key hash (e.g. a Bitcoin address).
  • {index} refers to the nth name this address created.

For example, the DID for is did:stack:v0:1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV-0, because the name was the first-ever name created by 1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV.

As another example, the DID for is did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-1. Here, the address 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg had created one earlier name in history prior to this one (which happens to be

The purpose of a DID is to provide an eternal identifier for a public key. The public key may change, but the DID will not.

Blockstack Core implements a DID method of its own in order to be compatible with other systems that use DIDs for public key resolution. In order for a DID to be resolvable, all of the following must be true for a name:

  • The name must exist
  • The name’s zone file hash must be the hash of a well-formed DNS zone file
  • The DNS zone file must be present in the BNS Atlas Network
  • The DNS zone file must contain a URI resource record that points to a signed JSON Web Token
  • The public key that signed the JSON Web Token (and is included with it) must hash to the address that owns the name

Not all names will have DIDs that resolve to public keys. However, names created by the Blockstack Browser will have DIDs that do.

Developers can programmatically resolve DIDs via the Python API:

>>> import blockstack
>>> blockstack.lib.client.resolve_DID('did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-1', hostport='')
{'public_key': '020fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc8'}

A RESTful API is under development.

DID Encoding for Subdomains

Every name and subdomain in BNS has a DID. The encoding is slightly different for subdomains, so the software can determine which code-path to take.

  • For on-chain BNS names, the {address} is the same as the Bitcoin address that owns the name. Currently, both version byte 0 and version byte 5 addresses are supported (i.e. addresses starting with 1 or 3, meaning p2pkh and p2sh addresses).

  • For off-chain BNS subdomains, the {address} has version byte 63 for subdomains owned by a single private key, and version byte 50 for subdomains owned by a m-of-n set of private keys. That is, subdomain DID addresses start with S or M, respectively.

The {index} field for a subdomain’s DID is distinct from the {index} field for a BNS name’s DID, even if the same created both names and subdomains. For example, the name has the DID did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0, because it was the first name created by 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg. However, 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg also created as its first subdomain name. The DID for is did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0. Note that the address SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i encodes the same public key hash as the address 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg (the only difference between these two strings is that the first is base58check-encoded with version byte 0, and the second is encoded with version byte 63).

You can see this play out in practice with the following code snippit:

>>> import blockstack
>>> blockstack.lib.client.get_name_record('', hostport='')['address']
>>> import virtualchain
>>> virtualchain.address_reencode('16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg', version_byte=63)
>>> blockstack.lib.client.resolve_DID('did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0', hostport='')
{'public_key': '020fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc8'}