About

The SOL DID method specification conforms to the requirements specified in the DID specification currently published by the W3C Credentials Community Group. For more information about DIDs and DID method specifications, please see the DID Primer and DID Spec.

Solana is a high-speed, low-fee public ledger based on a novel Proof-of-History consensus network. The SOL DID method is a method for storing DIDs and managing DID documents on Solana, built and maintained by Identity.com in conjunction with Solana.

 

SOL DID Method

The namestring that shall identify this DID method is: sol

A DID that uses this method MUST begin with the following prefix: did:sol. Per the DID specification, this string MUST be in lowercase. The remainder of the DID, after the prefix, is the NSI specified below.

Target System(s)

This DID method applies to the Solana mainnet network as well as the testnet and devnet clusters.

Namespace Specific Identifier (NSI)

The SOL DID scheme is defined by the following ABNF:

sol-did = "did:sol" *(":" network) ":" idstring
idstring = 40*48(base58char)
network = "testnet" / "devnet" / "localnet"
base58char = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "A" / "B" / "C"
    / "D" / "E" / "F" / "G" / "H" / "J" / "K" / "L" / "M" / "N" / "P" / "Q"
    / "R" / "S" / "T" / "U" / "V" / "W" / "X" / "Y" / "Z" / "a" / "b" / "c"
    / "d" / "e" / "f" / "g" / "h" / "i" / "j" / "k" / "m" / "n" / "o" / "p"
    / "q" / "r" / "s" / "t" / "u" / "v" / "w" / "x" / "y" / "z"

All SOL DIDs are base58 encoded using the Bitcoin/IPFS alphabets of a 32-byte key. The encoding uses most alphas and digits, omitting 0OIl to avoid readability problems. This gives an NSI length of between 40 and 48 characters, and it means that DIDs are case-sensitive and may not be case-normalized, even though the prefix is always lower-case.

Optionally, a network may be specified to indicate which Solana cluster contains the DID document.

Identifier Generation Method

The 32-byte key underlying a SOL DID is generated from the following deterministic algorithm. Given a DID owner with a public key on the x25519 ECC Curve, the DID owner key, the DID method ("sol"), a "bump seed", and the Solana program ID are hashed together.

The "bump seed" ensures the resultant address does not clash with the account address space, which lie on the Curve25519 elliptic curve.

The program ID is idDa4XeCjVwKcprVAo812coUQbovSZ4kDGJf2sPaBnM on all networks.

The bump seed is deterministically derivable off-chain as follows:

    Initialize the seed to 256 (2^8)
    Do:
      Decrement the seed by 1
      Hash the owner address, DID method, seed, and program ID
    While the resultant point is on the Curve25519 curve
  

A convenient regex to match SOL DID identifiers is:

^[1-9A-HJ-NP-Za-km-z]{40,48}$

A convenient regex to match the entire DID string is:

^did\:sol(\:(testnet|devnet|localnet))?\:[1-9A-HJ-NP-Za-km-z]{40,48}$

Examples

Valid SOL DIDs might be:

Operations

The following section outlines the DID operations for the did:sol method.

Create (Register)

A SOL DID can be created by combining the did:sol(:network) prefix with the AUTHORITY. An initial 'sparse' DID document can be generated without the need to register it on the Solana blockchain:

{
    "@context": [
        "https://w3id.org/did/v1.0",
        "https://w3id.org/sol/v1"
    ],
    "id": "did:sol:IDENTIFIER",
    "verificationMethod": [
        {
            "id": "did:sol:IDENTIFIER#key1",
            "type": "Ed25519VerificationKey2018",
            "controller": "did:sol:IDENTIFIER",
            "publicKeyBase58": "AUTHORITY"
        }
    ],
    "authentication": [
        "did:sol:IDENTIFIER#key1"
    ],
    "assertionMethod": [],
    "keyAgreement": [],
    "capabilityInvocation": [
        "did:sol:IDENTIFIER#key1"
    ],
    "capabilityDelegation": [],
    "service": [],
    "publicKey": [
        {
            "id": "did:sol:IDENTIFIER#key1",
            "type": "Ed25519VerificationKey2018",
            "controller": "did:sol:IDENTIFIER",
            "publicKeyBase58": "AUTHORITY"
        }
    ]
}
where:

AUTHORITY is the base58-encoded 32-byte x25519 public key of the DID owner,

IDENTIFIER is the DID method identifier derived from the authority.

Changing the default data of a SOL DID involves submitting a transaction to the Solana blockchain calling the "Initialize" instruction on the SOL Program. The only required input to this program is the public key of the 'authority', that is, the initial owner of the DID. The transaction must be signed by the authority.

The authority is a special key from which the DID is derived. It is always present in the verification methods list, and by default is added as the only key in the capabilityInvocations list, indicating that it is permitted to change the DID Document contents. It can, however be removed from the list by submitting an update instruction where the capabilityInvocation list is explicitly set (e.g. to the empty list or some other list of keys).

An optional additional SolData field may be added, containing additional document data, such as service endpoints or additional keys.

Fees and Rent

Updating a SOL DID on Solana incurs two types of fee, imposed by the Solana blockchain and paid in the chain's native token, SOL.

By default, the fee payer is the owner of the DID that will be created. However, the implementation supports a separate fee payer, that will incur the charges of registration/updating/deletion of the DID without having any permissions on the DID itself. This allows a central body to generate DIDs for its customers, without requiring them to have a SOL balance.

Read (Resolve)

A SOL DID record can be looked up on Solana,by stripping the did:sol: prefix from the DID, and network identifier if present, and looking up the resultant account on-chain. If no data is present on-chain, the generated DID document (see above) should be returned.

Anyone can query a DID record, by sending the above request. The response contains the DID document, encoded in a binary form defined by the Borsh serialization library. A client library is required to convert it to a DID Document. The schema for this format is defined in the reference implementation client.

Update (Replace)

To replace or update the DID document, the owner of the DID should send a transaction containing the "write" instruction to the SOL program. This transaction must be signed by a key that is referenced in the capabilityInvocation property.

The instruction parameters are:

Each value is expected to be calculated by a client library, rather than calculated manually (see the reference implementation for details).

For example, adding the following DID sub-document:

{
    "service": [
        {
            "id": "did:sol:IDENTIFIER#agent",
            "type": "AgentService",
            "serviceEndpoint": "https://hub.myhub.com/did:sol:IDENTIFIER/agent"
        }, {
            "id": "did:sol:ygGfLvAyuRymPNv2fJDK1ZMpdy59m8cV5dak6A8uHKa#messages",
            "type": "MessagingService",
            "serviceEndpoint": "https://hub.myhub.com/did:sol:IDENTIFIER/messages"
        }
    ]
}

to the above document, results in:
{
    "@context": [
        "https://w3id.org/did/v1.0",
        "https://w3id.org/sol/v1"
    ],
    "id": "did:sol:IDENTIFIER",
    "verificationMethod": [
        {
            "id": "did:sol:IDENTIFIER#key1",
            "type": "Ed25519VerificationKey2018",
            "controller": "did:sol:IDENTIFIER",
            "publicKeyBase58": "AUTHORITY"
        }
    ],
    "authentication": [
        "did:sol:IDENTIFIER#key1"
    ],
    "assertionMethod": [],
    "keyAgreement": [],
    "capabilityInvocation": [
        "did:sol:IDENTIFIER#key1"
    ],
    "capabilityDelegation": [],
    "service": [
        {
            "id": "did:sol:IDENTIFIER#agent",
            "type": "AgentService",
            "serviceEndpoint": "https://hub.myhub.com/did:sol:IDENTIFIER/agent"
        }, {
            "id": "did:sol:ygGfLvAyuRymPNv2fJDK1ZMpdy59m8cV5dak6A8uHKa#messages",
            "type": "MessagingService",
            "serviceEndpoint": "https://hub.myhub.com/did:sol:IDENTIFIER/messages"
        }
    ],
    "publicKey": [
        {
            "id": "did:sol:IDENTIFIER#key1",
            "type": "Ed25519VerificationKey2018",
            "controller": "did:sol:IDENTIFIER",
            "publicKeyBase58": "AUTHORITY"
        }
    ]
}

Only the AUTHORITY key can make this change, as that is the only one referenced inside capabilityInvocation.
An update can add an entry to or remove an entry from the capabilityInvocation list.
As with creation, an update transaction can specify a separate fee payer account to pay the transaction fee.

Delete (Revoke)

A SOL DID can be irreversibly deleted or revoked.

To revoke the document of the DID, the owner of the DID should send a transaction with a CloseAccount instruction. As with create and update, the owner of the DID is the default fee payer for the transaction, however, a separate fee payer account can be specified, in which case, this account will also receive any reimbursed rent in the account that stores the DID document.

When a SOL DID has been deleted, the DID document will resolve to the generated version.

Security Considerations

Attacks

Since all changes to SOL DIDs are locally-signed transactions on the Solana blockchain, it leverages the security of the audited Solana protocol. Any vulnerabilities in that protocol will apply to SOL.

SOL stores only public DIDs/DID Documents, which include public keys and service endpoints, on-chain.

Recovery From Key Compromise

It is recommended, although not enforced by SOL, that more than one key be included in the capabilityInvocation list. This allows a second trusted key to remove the reference to the first in the event of a key compromise. It is also recommended to include additional verification methods and keys that have permissions to perform actions with the DID (such as sign messages), but do not have permissions to update the document itself. This allows the capabilityInvocation keys to be stored in cold-storage, and only used when a key needs to be revoked. This protects against malicious rewriting of the document to add attackers' keys.

Privacy Considerations

DIDs should be assumed to be pseudonymous. Since the DID is registered on a decentralized ledger, it is not fully revocable, and this risk should be recognised by users of the DID method. As with all public pseudonymous persistent identifiers, there exists a risk of correlation when associating any other information with the DID in a way that exposes this information publicly.

Reference Implementations

It is expected that integrators of the SOL DID method do not interact with the Solana blockchain directly, but use a client library. A reference implementation, written in Typescript, is available at https://github.com/identity-com/sol-did and as an NPM library