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.
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.
This DID method applies to the Solana mainnet network as well as the testnet and devnet clusters.
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.
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}$
Valid SOL
DIDs might be:
did:sol:ygGfLvAyuRymPNv2fJDK1ZMpdy59m8cV5dak6A8uHKa
did:sol:devnet:6Na3uiqyRGZZQdd19RLCb6kJHR51reFdhXzAuc6Y8Yef
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.
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.
Each action (register, update, delete) incurs a transaction fee. This fee is independent of the size of the document.
Document registration incurs rent, A fee charged on data storage on Solana. The cost of rent depends on the size of the document and the length of time that the DID should persist on Solana.
It is recommended to deposit sufficient rent to ensure exemption from garbage-collection, and this is the assumption made by the reference implementation client. This rent is then reimbursed upon revocation of the DID.
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.
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.
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.
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.
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.
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.