Category | Status |
---|---|
This ADR defines the cheqd DID method and describes the identity entities, queries, and transaction types for the cheqd network: a purpose-built self-sovereign identity (SSI) network based on the Cosmos blockchain framework.
Decentralized identifiers (DIDs) are a type of identifier that enables verifiable, decentralized digital identity. A DID refers to any subject (for example, a person, organization, thing, data model, abstract entity, and so on) as determined by the controller of the DID.
Hyperledger Indy is a verifiable data registry (VDR) built for DIDs with a strong focus on privacy-preserving techniques. It is one of the most widely-adopted SSI blockchain ledgers. Most notably, Indy is used by the Sovrin Network.
The Sovrin Foundation initiated a project called libsovtoken
in 2018 to create a native token for Hyperledger Indy. libsovtoken
was intended to be a payment handler library that could work with libindy
and be merged upstream. This native token would allow interactions on Hyperledger Indy networks (such as Sovrin) to be paid for using tokens.
Due to challenges the project ran into, the libsovtoken
codebase saw its last official release in August 2019.
The cheqd network aims to support similar use cases for SSI as seen on Hyperledger Indy networks, with a similar focus on privacy-resspecting techniques.
Since the core of Hyperledger Indy's architecture was designed before the W3C DID specification started to be defined, the Indy DID Method (did:indy
) has aspects that are not fully-compliant with latest specifications.
However, the rationale for why the cheqd team chose the Cosmos blockchain framework instead of Hyperledger Indy were primarily down to the following reasons:
Hyperledger Indy is a permissioned ledger: Indy networks are permissioned networks where the ability to have write capability is restricted to a limited number of nodes. Governance of such a permissioned network is therefore also not decentralised.
Limitations of Hyperledger Indy's consensus mechanism: Linked to the permissioned nature of Indy are the drawbacks of its Plenum Byzantine Fault Tolerant (BFT) consensus mechanism, which effectively limits the number of nodes with write capability to approximately 25 nodes. This limit is due to limited transactions per second (TPS) for an Indy network with a large number of nodes, rather than a hard cap implemented in the consensus protocol.
Wider ecosystem for token functionality outside of Hyperledger Indy: Due to its origins as an identity-specific ledger, Indy does not have a fully-featured token implementation with sophisticated capabilities. Moreover, this also impacts end-user options for ecosystem services such as token wallets, cryptocurrency exchanges, custodianship services etc that would be necessary to make a viable, enterprise-ready SSI ledger with token functionality.
By selecting the Cosmos blockchain framework, the maintainers of the cheqd project aim to address the limitations of Hyperledger Indy outlined above. However, with an eye towards interoperability, the cheqd project aims to use Hyperledger Aries for ledger-related peer-to-peer interactions.
Our aim is to support the functionality enabled by identity-domain transactions in by Hyperledger Indy into cheqd-node
. This will partly enable the goal of allowing use cases of existing SSI networks on Hyperledger Indy to be supported by the cheqd network.
The following identity-domain transactions from Indy were considered:
NYM
: Equivalent to "DIDs" on other networks
ATTRIB
: Payload for DID Document generation
SCHEMA
: Schema used by a credential
CRED_DEF
: Credential definition by an issuer for a particular schema
REVOC_REG_DEF
: Credential revocation registry definition
REVOC_REG_ENTRY
: Credential revocation registry entry
Revocation registries for credentials are not covered under the scope of this ADR. This topic is discussed separately in a future ADR as there is ongoing research by the cheqd project on how to improve the privacy and scalability of credential revocations.
Schemas and Credential Definitions are also not covered under the scope of this ADR. Their implementation is covered in ADR 002: DID-Linked Resources.
did:cheqd
)The method-name
for the cheqd DID Method will be identified by the string cheqd
.
A DID that uses the cheqd DID method MUST begin with the prefix did:cheqd
. This prefix string MUST be in lowercase. The remainder of the DID, after the prefix, is as follows:
The cheqd DID method's method-specific identifier (method-specific-id
) is made up of the namespace
component. The namespace
is defined as a string that identifies the cheqd network (e.g., "mainnet", "testnet") where the DID reference is stored. Different cheqd networks may be differentiated based on whether they are production vs non-production, governance frameworks in use, participants involved in running nodes, etc.
The namespace
associated with a certain network/ledger is stored in the genesis file on the node and cannot be changed by validators vote. A namespace is optional and can be omitted.
A did:cheqd
DID must be unique. The syntax of the unique-id
component may be defined as a Universally Unique Identifier (UUID) generated by the creator(s) of the DID. UUIDs are the preferred unique identifier format for cheqd network.
Usage of UUID-style identifiers significantly simplifies the generation and implementation of unique identifiers, with extremely-low probability of a collission where the same UUID is generated independently.
Any client application can generate these UUIDs using their own preferred implementation in any programming language, as opposed to the method-specific logic required for Indy-style DID identifiers.
Alternatively, the unique-id
may also be generated similar to the did:indy method
from the initial public key of the DID (e.g., base58 encoding of the first 16 bytes of the SHA256 of the first Verification Method Ed25519
public key). This unique-id
format is referred to as the "Indy-style" unique identifier in our documentation.
Support for Indy-style unique identifiers makes compatibility with Indy-based client SDKs, such as those based on Hyperledger Aries.
If no namespace
is specified, it assumed to be default namespace
for the network/ledger the request is targetted at. This will generally be mainnet
for the primary production cheqd network.
did:cheqd
methodThe cheqd DID method ABNF to conform with DID syntax guidelines is as follows:
Note: The
*id-char unique-id
must be 16 bytes of Indy-style base58 encoded identifier.
Where the formal definition of UUIDs is represented using this ABNF:
did:cheqd
identifiersA DID written to the cheqd "mainnet" ledger namespace
with an Indy-style identifier:
A DID written to the cheqd "testnet" ledger namespace
with an Indy-style identifier:
An Indy-style DID where no namespace is defined, where the namespace
would default to the one defined on ledger where it's published (typically, mainnet
):
A UUID-style DID on cheqd "mainnet" namespace
:
A UUID-style DID where no namespace is defined, where the namespace
would default to the one defined on ledger where it's published (typically, mainnet
):
A DID Document ("DIDDoc") associated with a cheqd DID is a set of data describing a DID subject. The representation of a DIDDoc when requested for production from a DID on cheqd networks MUST meet the DID Core specifications.
The following elements are needed for a W3C specification compliant DIDDoc representation:
@context
(optional): A list of strings with links or JSONs for describing specifications that this DID Document is following to.
id
: Target DID with cheqd DID Method prefix did:cheqd:<namespace>:
and a unique-id
identifier.
controller
(optional): A list of fully qualified DID strings or one string. Contains one or more DIDs who can update this DIDdoc. All DIDs must exist.
verificationMethod
(optional): A list of Verification Methods
authentication
(optional): A list of strings with key aliases or IDs
assertionMethod
(optional): A list of strings with key aliases or IDs
capabilityInvocation
(optional): A list of strings with key aliases or IDs
capabilityDelegation
(optional): A list of strings with key aliases or IDs
keyAgreement
(optional): A list of strings with key aliases or IDs
service
(optional): A set of Service Endpoint maps
alsoKnownAs
(optional): A list of strings. A DID subject can have multiple identifiers for different purposes, or at different times. The assertion that two or more DIDs refer to the same DID subject can be made using the alsoKnownAs
property.
"diddoc:<id>" -> {DIDDoc, DidDocumentMetadata, txHash, txTimestamp }
didDocumentMetadata
is created by the node after transaction ordering and before adding it to a state.
Each DID Document MUST have a metadata section when a representation is produced. It can have the following properties:
created
(string): Formatted as an XML Datetime normalized to UTC 00:00:00 and without sub-second decimal precision, e.g., 2020-12-20T19:17:47Z
.
updated
(string): The value of the property MUST follow the same formatting rules as the created property. The updated
field is null
if an Update operation has never been performed on the DID document. If an updated property exists, it can be the same value as the created property when the difference between the two timestamps is less than one second.
deactivated
(string): If DID has been deactivated, DID document metadata MUST include this property with the boolean value true
. By default this is set to false
.
versionId
(string): A UUID string that represents the version identifier of the DID Document.
resources
(list of resources metadata referred to as Resource previews)| optional. Cannot be changed by CreateDID or UpdateDID transactions. cheqd ledger stores only the resource identifiers in the DID Doc metadata. The remainder of the resources' metadata is added when a DID is resolved.
previousVersionId
(string): A UUID string that represents the version identifier of the previous version of the DID Document. The previousVersionId
field is an empty string if an Update operation has never been performed on the DID document
nextVersionId
(string): A UUID string that represents the version identifier of the next version of the DID Document. The nextVersionId
field is an empty string if an Update operation has never been performed on the DID document
Verification methods are used to define how to authenticate / authorise interactions with a DID subject or delegates. Verification method is an OPTIONAL property.
id
(string): A string with format did:cheqd:<namespace>#<key-alias>
controller
: A string with fully qualified DID. DID must exist.
type
(string)
publicKeyJwk
(map[string,string]
, optional): A map representing a JSON Web Key that conforms to RFC7517. See definition of publicKeyJwk
for additional constraints.
publicKeyBase58
(optional): A base58-encoded string.
publicKeyMultibase
(optional): A base58-encoded string that conforms to a MULTIBASE encoded public key.
Note: A single verification method entry cannot contain more than one of publicKeyJwk
, publicKeyBase58
and publicKeyMultibase
, but must contain at least one of them.
Services can be defined in a DIDDoc to express means of communicating with the DID subject or associated entities.
id
(string): The value of the id
property for a Service MUST be a URI conforming to RFC3986. A conforming producer MUST NOT produce multiple service entries with the same ID. A conforming consumer MUST produce an error if it detects multiple service entries with the same ID. It has a follow formats: <DIDDoc-id>#<service-alias>
or #<service-alias>
.
type
(string): The service type and its associated properties SHOULD be registered in the DID Specification Registries
Since cheqd-node is built using the Cosmos SDK, the data stored directly on ledger is formatted in Protobuf and is transformed back into compliant JSON client-side on request.
Example of how cheqd-node stores verification_method
id
(string): A string with format did:cheqd:<namespace>#<key-alias>
controller
: A string with fully qualified DID. DID must exist.
verification_method_type
(string): A string that represents type of verification method. Supported: Ed25519VerificationKey2018
, Ed25519VerificationKey2020
, JsonWebKey2020
.
verification_material
(string): It represents the exact decoded string value of public key for the verification method. Supported types of public key representations are: publicKeyBase58
, publicKeyMultibase
, publicJwk
.
This operation updates the DID Document associated with an existing DID of type did:cheqd:<namespace>
.
signatures
: UpdateDidRequest
should be signed by all controller
private keys. This field contains a dict
structure with the key URI from DIDDoc.authentication
, as well as signature values.
id
: Fully qualified DID of type did:cheqd:<namespace>
.
versionId
: Transaction hash of the previous DIDDoc version. This is necessary to provide replay protection. The previous DIDDoc versionId
can fetched using a get DID query.
controller, verificationMethod, authentication, assertionMethod, capabilityInvocation, capabilityDelegation, keyAgreement, service, alsoKnownAs, context
: Optional parameters in accordance with DID Core specification properties.
This operation deactivates the DID for a given did:cheqd:<namespace>
. Once deactivated, a DID cannot be re-activated or any DIDDoc update operations carried out.
id
: Fully qualified DID of type did:cheqd:<namespace>
.
signatures
: DeactivateDidDocRequest
should be signed by all controller
private keys. This field contains controller key URIs and signature values.
DIDDocs associated with a DID of type did:cheqd:<namespace>
can be resolved using the GetDidDoc
query to fetch a response from the ledger. The response contains:
did_doc
: DIDDoc associated with the specified DID in a W3C specification compliant DIDDoc structure.
metadata
: Contains the MUST have DIDDoc metadata associated with a DIDDOc.
DID resolution requests can be sent to the Tendermint RPC interface for a node by passing the fully-qualified DID.
The response is returned as a Protobuf, which can be converted to JSON client-side.
For creating a new DID or update the DIDDoc associated with an existing DID, the requested should be signed by all controller
signatures.
To update a DIDDoc fragment without a controller
(any field except VerificationMethods
), the request MUST be signed by the DID's controller
(s).
To update a DIDDoc fragment that has its own controller
(s), the request MUST be signed by the DID's controller
(s) and the DIDDoc fragment's controller
(s).
Changing the controller
(s) associated with a DID requires a list of signatures as before for changing any field.
One of the key design decisions in the cheqd DID method is to use separate sets of key pairs for Cosmos / node layer transactions and identity payloads.
Keypairs and accounts on the Cosmos node layer are public, and can be crawled/explored by inspecting transactions on a node or through a block explorer. This therefore poses a privacy risk through correlation, if the identity payloads were signed using the same keys.
By splitting the keys/accounts for the two layers, we account for identity payloads being signed using keys that can be kept off-ledger.
This also allows for uses cases where the key owners/controllers at the identity layer are different than the key/account owners at the Cosmos node layer. In essence, that this allows is it removes the need for a DID's controllers to also have an account on the cheqd network ledger.
Further discussion on how these boundaries are separated in implementation, with one specific implementation library, is described in cheqd node ADR 003: Command Line Interface (CLI) tools
NYM
transactions to DID
transactionsNYM is the term used by Hyperledger Indy for DIDs. cheqd uses the term DID
instead of NYM
in transactions, which should make it easier to understand the context of a transaction easier by bringing it closer to W3C DID terminology used by the rest of the SSI ecosystem.
role
field from DID transactionsHyperledger Indy is a public-permissioned distributed ledger and therefore use the role
field to distinguish transactions from different types of nodes. As cheqd networks are public-permissionless, the role
scope has been removed.
ATTRIB
transactions droppedATTRIB
was originally used in Hyperledger Indy to add document content similar to DID Documents (DIDDocs). The cheqd DID method replaces this by implementing DIDDocs for most transaction types.
To support the cheqd Resource Module, cheqd ledger includes a reference to resource previews within the DIDDoc metadata.
Identity entities and transactions for the cheqd network may differ in name from those in Hyperledger Indy, but aim enable equivalent support for privacy-respecting SSI use cases.
The differences stem primarily from aiming to achieve better compliance with the W3C DID Core specification and architectural differences between Hyperledger Indy and Cosmos SDK (used to build cheqd-node
).
With better compliance against the DID Core specification, the goal of the cheqd DID method is to maximise interoperability with compatible third-party software librarires, tools and projects in the SSI ecosystem.
The cheqd DID method does not aim to be 1:1 compatible in API methods with did:indy
. It makes opinionated choices to not implement certain transaction types, which in our analysis have been superseded by new developments in the W3C DID Core specification.
Support for Indy-style DID unique identifiers is intended to provide a compatibility mode with existing Indy-based client applications.
cheqd-node
release v0.1.19 and earlier had a transaction type called NYM
which would allow writing/reading a unique identifier on ledger. However, this NYM
state was not fully defined as a DID method and did not store DID Documents associated with a DID. This NYM
transaction type is deprecated and the data written to cheqd testnet with legacy states will not be retained.
Design decisions defined in this ADR aim to make the cheqd DID method compliant with the W3C DID Core specification.
Usage of UUID-style identifiers significantly simplifies the generation and implementation of unique identifiers, since any client application can generate these UUIDs using their own preferred implementation in any programming language, as opposed to the method-specific logic required for Indy-style DID identifiers.
As the client/peer-to-peer exchange layer (at least in the implementation provided by VDR Tools SDK) is built on a library that supports Hyperledger Aries, extending Aries implementations to other W3C compliant DID methods should become simpler for the SSI ecosystem.
Trying to maintain backwards-compatibility with Hyperledger Indy APIs means some functionality will not be available for legacy client applications which cannot support non-Indy DID Document elements, e.g., multiple verification methods in the same DIDDoc.
DID transaction operations at the moment must be assembled using a client-side library with DID specification identity standards support, and then wrapped up inside a Cosmos transaction that is sent to the Tendermint RPC or Cosmos SDK gRPC interface. We aim to build client apps/SDKs that can be used by developers to make the process of interacting with the ledger simpler.
Hyperledger Indy official project background on Hyperledger Foundation wiki
indy-node
GitHub repository: Server-side blockchain node for Indy (documentation)
indy-plenum
GitHub repository: Plenum Byzantine Fault Tolerant consensus protocol; used by indy-node
(documentation)
Indy DID method (did:indy
)
Hyperledger Aries official project background on Hyperledger Foundation wiki
aries
GitHub repository: Provides links to implementations in various programming languages
aries-rfcs
GitHub repository: Contains Requests for Comment (RFCs) that define the Aries protocol behaviour
Cosmos blockchain framework official project website
cosmos-sdk
GitHub repository (documentation)
libsovtoken
: Sovrin Network token library
Authors
Ankur Banerjee, Alexandr Kolesov, Alex Tweeddale, Brent Zundel, Renata Toktar, Richard Esplin
ADR Stage
ACCEPTED
Implementation Status
Implemented
Start Date
2021-09-23
Last Updated
2023-02-06