§ Indy DID Method
Specification Status: Version 1.0 (Draft)
Latest Draft:
https://github.com/hyperledger/indy-did-method
Editors:
- Stephen Curran
- Paul Bastian
- Daniel Hardman
- Char Howland
- Christian Bormann
- Dominic Wörner
- Daniel Bluhm
- Kyle Den Hartog
- Participate:
- GitHub repo
- Commit history
§ About
The Indy DID method specification conforms to the requirements 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.
§ Abstract
Indy is a public ledger designed specifically and only for privacy-preserving self-sovereign identity. A Hyperledger Indy ledger is designed specifically to enable the use of verifiable credentials, allowing credential issuers to publish data necessary for issuing verifiable credentials and constructing presentations from those verifiable credentials. This specification covers how DIDs on an Indy ledger are managed and the operations for creating, reading, updating, and deleting DIDs.
§ Indy Ledger Objects: Glossary
Instances of Hyperledger Indy networks persist different kind of (internal) data objects in the ledger. The following section describes those objects.
- NYM
-
A NYM (short for “Verinym”) is associated with the Legal Identity of an Identity Owner and is a Hyperledger Indy specific term for a data object, which holds DID data of one concrete identity returned during DID resolution. While a NYM can be read from a Hyperledger Indy Node by any client, a NYM can only be written to a Hyperledger Indy network as long as the writing entity possess the proper permissions.
-
A NYM object itself does not conform to the Decentralized Identifiers (DIDs) Core specification scheme but rather includes all DID related data of a single identity and therefore its resolution into a DID document does. Therefore writing a NYM to a Hyperledger Indy instance basically results in writing a DID to the ledger. The author of a NYM write transaction is then the owner of the NYM respectively and its embedded DID.
-
When reading NYM transaction from the ledger, clients transform / extract the NYM data into a DID document. Often the terms “NYM” and “DID” are used synonymously, although a “NYM” is “just” Hyperledger Indy’s specific way of storing DIDs into the ledger.
- ATTRIB - Deprecated
-
A Hyperledger Indy ATTRIB (short for “attribute”) object extends a specific DID (also known as NYM) of its owner with further information (attributes) and can be read from a Hyperledger Indy Node by any client. An ATTRIB object can only be written to a Hyperledger Indy network by an owner of the DID on that network.
-
The use of ATTRIB is deprecated with the introduction of the
did:indy
DID Method. The only common use of ATTRIBs in Hyperledger Indy prior todid:indy
was to define DIDDoc service endpoints for a DID. Since withdid:indy
such a service endpoint can be added directly to the DID (along with any other DIDDoc data) there is no need to continue the use of the older ATTRIBendpoint
convention. While a Hyperledger Indy client (such as Indy VDR) MAY continue to try to resolve anendpoint
ATTRIB when there is no DIDDoc content in a resolved DID, the ongoing practice of using an ATTRIB for that or any other purpose is discouraged. -
The
did:indy
method introduces legacy support for retrieving the service endpoint of a past version of an attribute byversionId
orversionTime
, using a process similar to resolving DID Versions by these parameters. - SCHEMA
-
A SCHEMA object is a template that defines a set of attribute (names) which are going to be used by issuers for issuance of Verifiable Credentials within a Hyperledger Indy network. SCHEMAs have a name, version and can be written to the ledger by any entity with proper permissions. Schemas can be read from a Hyperledger Indy Node by any client.
-
SCHEMAs define the list of attribute (names) of issued credentials based on a CRED_DEF (see below).
- CRED_DEF
-
A CRED_DEF (short for “credential definition”) object contains data required for credential issuance as well as credential validation and can be read by any Hyperledger Indy client. A CRED_DEF object references a SCHEMA, references a DID of the issuer and can be written by any issuer who intends to issue credentials based on that specific SCHEMA to the ledger and has the proper permissions in doing so. A public key of the issuer is included within the CRED_DEF which allows validation of the credentials signed by the issuer’s private key. When credentials are issued by using the issuers CRED_DEF, the attribute (names) of the SCHEMA have to be used.
-
Revokable Verifiable Credentials require CRED_DEFs which also reference a REV_REG_DEF (see below).
- CLAIM_DEF - Deprecated
-
The deprecated term CLAIM_DEF is sometimes used to describe a CRED_DEF, particularly in existing Hyperledger Indy code.
- REV_REG_DEF
-
A REV_REG_DEF object (short for “revocation registry definition”) contains information required for verifiers in order to enable them to verify whether a (revokable) verifiable credential has been revoked by the issuer since issuance.
-
REV_REG_DEFs are only needed for revokable verifiable credentials and are most commonly written to the ledger by the owner of a CRED_DEF immediately after the CRED_DEF has been written. They can be read from a Hyperledger Indy Node by any client and are updated in case of the revocation of a credential, which is based on the used CRED_DEF.
-
Further details about Hyperledger Indy’s revocation process can be found here.
- REV_REG_ENTRY
-
A REV_REG_ENTRY object (short for “revocation registry entry”) marks the current status of one or more revokable verifiable credentials (“revoked” or “not revoked”) in the ledger in a privacy preserving manner. A REV_REG_ENTRY is written by the owner of a REV_REG_DEF respectively the issuer of the credential(s) based on a CRED_DEF and its REV_REG_DEF.
-
Any REV_REG_ENTRY condensed with further required information can be read by any Hyperledger Indy client.
-
Further details about Hyperledger Indy’s revocation process can be found here.
- Indy VDR
-
Hyperledger Indy VDR (for “Verifiable Data Registry”) is an open source implementation of an Indy client/resolver for both DIDs and other Indy objects. The repository is called indy-vdr and can be found here.
§ Differences from did:sov
Early instances of Indy Networks used the did:sov
DID Method. The following summarizes the differences between that did:sov
and did:indy
.
- A
did:indy
DID includes a namespace component that enables resolving a DID to a specific instance of an Indy network (e.g. Sovrin, IDUnion, etc.). - Identifiers for Indy ledger objects other than NYMs are adjusted to contain a namespace component.
did:indy
DID validation is determined by NYM transactionversion
, as described in the DID Creation section. These restrictions MUST be enforced by the ledger.- The specification includes rules for transforming a NYM into a DIDDoc that meets the DID Core Specification.
- An optional NYM data item allows entities to extend the DIDDoc returned from a NYM in arbitrary ways.
- The controller can decide whether the DIDDoc will be JSON or JSON-LD.
- Before writing a NYM to the ledger, the NYM content is verified to ensure that transforming the NYM to a DIDDoc produces a valid JSON and may include DIDDoc validity checking.
- The transformation of a read NYM to a DIDDoc is left to the client of an Indy ledger.
- A convention for storing Indy network instance config (“genesis”) files in a Hyperledger Indy project GitHub repository (“indy-did-networks”) is introduced.
§ Target System(s)
The did:indy
DID method applies to all DIDs which are anchored to a Hyperledger Indy Ledger and which comply with these specific conventions.
§ Motivation and Assumptions
§ Assumption: Number of Indy Instances
We are anticipating that there will be at most on the order of “low hundreds” of Indy network instances, with the potential for several (usually 3) subnamespaces per network instance for production, test (staging), and development deployments. This assumption is based on the likelihood of their being some (likely small) number of global Indy instances, and some number of national Indy instances. Assuming at most one per country, we would have around 200-300 total, leading to the anticipated maximum of “low hundreds” of Indy network instances.
§ Including a Network-specific Identifier
Including a network-specific identifier within an Indy DID identifier enables a “network of networks” capability where an Indy DID can be uniquely resolved to a specific DIDDoc stored on a specific Indy network using a common resolver software component. Given a did:indy
DID, the network-specific identifier embedded in the DID can be extracted to determine where to send the request to resolve the DID Doc. This enables several useful properties:
- Decentralization: Additional instances of networks can be deployed and easily used.
- Scalability: Additional DID ledgers can be deployed and DIDs on those ledgers easily referenced.
- Fit for purpose: A DID ledger can be deployed and easily used for specific purposes, such as part of a nation’s critical infrastructure.
- Governance: A DID ledger can be deployed under a specific governance structure appropriate to those writing to that ledger.
§ Aligning Indy with the DID Core Specification
The DID Indy method specification formalizes the transformation of an Indy ledger object (a NYM) into a DIDDoc as defined in the DID Core specification from W3C, ensuring that identifiers written to and read from Indy ledgers are W3C standard DIDs.
§ Resolving a DIDDoc in a single transaction
Previous approaches to resolving Indy ledger objects into DIDDocs required the client read one or more ledger objects (notably, NYMs and ATTRIBs) before assembly. This is at best “challenging” for the client, and at worst, extremely slow without specialized ledger support, particularly when a non-current version of the DID is being resolved. A preferred approach is to enable the resolution of a DID via a single read transaction that returns a single object off the ledger, including a state proof for that object.
§ Cross-Ledger Object References
The NYM controller of all objects on an Indy ledger MUST reside on the same Indy ledger as the object. Thus, the DID (e.g. the Indy NYM) of the Issuer of a verifiable credential type must reside on the same ledger as the CRED_DEF, REV_REG_DEF and REV_REG_ENTRY objects for that type of verifiable credential.
Note that the constraint above does not apply to a SCHEMA referenced by a CRED_DEF, since a CRED_DEF may use a SCHEMA written by another NYM. As such, a CRED_DEF may reference a SCHEMA on a different Indy ledger.
§ Indy DID Method Identifiers
The did:indy Method DID identifier has four components that are concatenated to make a DID specification conformant identifier. The components are:
- DID: the hardcoded string
did:
to indicate the identifier is a DID - DID Indy Method: the hardcoded string
indy:
indicating that the identifier uses this DID Method specification. - DID Indy Namespace: a string that identifies the name of the primary Indy ledger, followed by a
:
. The namespace string may optionally have a secondary ledger name prefixed by a:
following the primary name. If there is no secondary ledger element, the DID resides on the primary ledger, else it resides on the secondary ledger. By convention, the primary is a production ledger while the secondary ledgers are non-production ledgers (e.g. staging, test, development) associated with the primary ledger. Examples include,sovrin
,sovrin:staging
andidunion
. - Namespace Identifier: a identifier unique to the given DID Indy namespace. The identifier may be self-certifying, meaning that the identifier is derived from the initial verkey associated with the identifier. See the DID Creation section of this document for the derivation details.
The components are assembled as follows:
did:indy:<namespace>:<namespace identifier>
Some examples of did:indy
DID Method identifiers are:
- A DID written to the Sovrin MainNet ledger:
did:indy:sovrin:7Tqg6BwSSWapxgUDm9KKgg
- A DID written to the Sovrin StagingNet ledger:
did:indy:sovrin:staging:6cgbu8ZPoWTnR5Rv5JcSMB
- A DID on the IDUnion Test ledger:
did:indy:idunion:test:2MZYuPv2Km7Q1eD4GCsSb6
§ Other Indy Ledger Object Identifiers
Indy ledgers may hold object types other than DIDs, and each of the other object types must also be resolvable to a specific Indy network instance. The identifiers for these objects are used in data structures that are exchanged by Indy clients (e.g. Aries Agents)–verifiable credentials, presentation requests, presentations and so on. Transitioning to the did:indy
DID Method requires transitioning Indy clients/resolvers to use the identifiers defined in this section.
§ DID URLs for Indy Object Identifiers
The structure of identifiers for all non-DID Indy ledger objects is the following DID URL structure, based on the DID of the object’s DID controller:
<did>/<object-family>/<object-family-version>/<object-type>/<object-type-identifier>
The components of the DID URL are:
<did>
thedid:indy
DID of the object-owning controller<object-family>
family of the object<object-family-version>
version of the object family<object-type>
one of SCHEMA, CRED_DEF, REV_REG_DEF, REV_REG_ENTRY, ATTRIB<object-type-identifier>
an object type unique identifier defined by Indy by object type.
The data returned from resolving such DID URLs is the ledger object and relevant state proof; the same data returned from the Indy Node read object transactions, such as the GET_SCHEMA transaction, and dependent on the type of the object.
Since indy allows special characters within the names of the different ledger objects, percent encoding according to Section 2 of RFC3986 has to be applied to access these objects via DID URLs.
While there are no restrictions regarding the used characters, we strongly encourage avoiding special characters in the names of ledger objects.
The following sections cover each ledger object type, providing:
- an example DID URL identifier,
- a link to an example object residing on the Sovrin MainNet Indy ledger (courtesy of indyscan.io),
- the appropriate object family and version,
- the format of the response when resolving the DID URL,
- the pre-
did:indy
identifier for each object, and - notes about the elements of the pre-
did:indy
identifier.
This first version of the did:indy
DID Method will use an <object-family>
value of anoncreds
and an <object-family-version>
of v0
to match the
pre-specification, open source version of anoncreds as implemented in the indy-sdk.
Later versions of the did:indy
specification will use a higher <object-family-version>
as the AnonCreds standardization work proceeds
and the required dependency on Hyperledger Indy is removed. In this initial version, the DID URLs are closely aligned with the existing object identifiers.
§ Schema
DID URL: did:indy:sovrin:F72i3Y3Q4i466efjYJYCHM/anoncreds/v0/SCHEMA/npdb/4.3.4
- Object Family:
anoncreds
- Family Version:
v0
- Name, example
npdb
: The client-defined schema name - Schema Version, example
4.3.4
: The client-defined version of the SCHEMA
Response: Same as the Indy Node GET_SCHEMA Txn
Existing identifier: F72i3Y3Q4i466efjYJYCHM:2:npdb:4.3.4
2
is the enumerated object type- Name and Schema Version elements defined above.
§ Cred Def
DID URL: did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/CLAIM_DEF/56495/npdb
- Object Family:
anoncreds
- Family Version:
v0
- Schema ID, example
56495
: A unique identifier for the schema upon which the CredDef is defined. In v0, the value is also the Hyperledger Indy instance sequence number for the Schema object used by this Cred Def. In later versions, we expect that the schema identifier will either be removed from the CredDef DID URL, or take a different form. - Name, example
npdb
: The client-defined cred def name.
Response: Same as the Indy Node GET_CLAIM_DEF Txn
Existing identifier: 5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb
3
is the enumerated object typeCL
is the signature type for the cred def, which isCL
for all cred defs on all existing Indy ledgers- Schema ID and Name elements defined above.
We recommend that AnonCred credential issuers use a unique Name item per Cred Def, and not rely on the embedded Schema ID
remaining in the DID URL for a Cred Def in future versions of the did:indy
method.
§ Revocation Registry Definition
DID URL: did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/REV_REG_DEF/56495/npdb/TAG1
- Object Family:
anoncreds
- Family Version:
v0
- Schema ID, example
56495
: A unique identifier for the schema upon which the CredDef/RevReg are defined. In v0, the value is also the Hyperledger Indy instance sequence number for the Schema object used by this Cred Def. In later versions, we expect that the schema identifier will either be removed from the RevReg DID URL, or take a different form. - Cred Def Name, example
npdb
: The client-defined cred def name. - Tag, example
TAG1
: The client-defined rev reg tag (name).
Response: Same as the Indy Node GET_REVOC_REG_DEF Txn
Existing Identifier: 5nDyJVP1NrcPAttP3xwMB9:4:5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb:CL_ACCUM:TAG1
4
is the enumerated object type5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb
is the identifier of the associated Cred Def- Tag element defined above.
§ Revocation Registry Entry
DID URL: did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/REV_REG_ENTRY/56495/npdb/TAG1
- Object Family:
anoncreds
- Family Version:
v0
- Schema ID, example
56495
: A unique identifier for the schema upon which the CredDef/RevReg are defined. In v0, the value is also the Hyperledger Indy instance sequence number for the Schema object used by this Cred Def. In later versions, we expect that the schema identifier will either be removed from the RevReg DID URL, or take a different form. - Cred Def Name, example
npdb
: The client-defined cred def name. - Tag, example
TAG1
: The client-defined rev reg tag (name).
The DID URL resolution response depends on the query parameters used, as follows:
- None
- Response is the same as the Indy Node GET_REVOC_REG Txn with the current time used for the
versionTime
.
- Response is the same as the Indy Node GET_REVOC_REG Txn with the current time used for the
?versionTime=<XML Datetime>
- Response is the same as the Indy Node GET_REVOC_REG Txn.
?from=<XML Datetime>&to=<XML Datetime>
- Response is the same as the Indy Node GET_REVOC_REG_DELTA Txn
- At least one of the parameters has to be set.
- If only
from
is set, thento
is implicitly set to the current time. - If only
to
is set, then all deltas up to this time are returned.
Existing Identifier: 5:5nDyJVP1NrcPAttP3xwMB9:4:5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb:CL_ACCUM:TAG1
5
is the enumerated object type- The remainder of the identifier is the identifier for the applicable Revocation Registry
§ ATTRIB
No DID URL representation is defined for the Hyperledger Indy ATTRIB object, as
the use of the ATTRIB object is deprecated with the introduction of the
did:indy
DID Method. Where an ATTRIB might have been used in the past, an Indy
client updated for did:indy
should put the required data directly into the
diddocContent
item in a DID (NYM) update transaction.
§ Finding Indy Ledgers
To connect and read or write from a Hyperledger Indy network instance, a client must have the configuration file (in Indy, called the “gensis” file) for the network. Given a did:indy
DID (e.g. did:indy:<namespace>:<namespace identifier>
), the Indy network instance on which the DID resides is known. However, there remains a challenge for the entity interested in resolving the DID—finding the genesis file for that network instance. The following documents two mechanisms resolvers can use to access required genesis files.
§ Static
A client that will resolve Hyperledger Indy DIDs can be statically configured to “know” about a set of Indy networks by loading the files on startup. The files would be collected from the node operators in some way by those deploying the client software (e.g. an Aries Wallet).
When a static list of Indy networks is used, DIDs from other, organically discovered networks not on the list cannot be resolved by the client.
§ Dynamic using GitHub
The Hyperledger Indy GitHub repo indy-did-networks
enables Indy DID network operators to publish their network genesis files in a standard way. Within the repo, the folder “networks” contains a folder per primary network. Within each network folder is the genesis file for the primary network, and folders (containing a corresponding genesis file) for each subspace network. The naming format for the genesis files is:
pool_transactions_genesis.json
For example, the Sovrin MainNet, StagingNet and BuilderNet genesis files will be in the repo as:
networks/sovrin/pool_transactions_genesis.json
networks/sovrin/staging/pool_transactions_genesis.json
networks/sovrin/builder/pool_transactions_genesis.json
The committers to the repo for each network SHOULD include in the folder at least a README.md file with information about the network, plus any additional documents about the ledger instance, such as Governance Framework documents.
§ Client Usage
A client may retrieve selected network genesis files from the repo to use as their set of static files, as described in the previous section. The developers of the clients can monitor the repo for changes to the genesis files that they are using.
If a DID is obtained by the client that is from a network not already known by the client, the client MAY look for the unknown (to the client) network in the GitHub repo and decide to use (or not) the associated genesis file to connect to the network.
The security policy of the client (and perhaps the user of the client) might give options about handling unknown networks, such as:
- Never connect.
- Review and connect if permission from client operator granted.
- Always connect if the genesis file for the network can be found.
§ Repository Maintenance
Each contributing network instance operator maintains copies of their genesis files and supporting documents in the GitHub repo by submitting Pull Requests (PRs) to the repo. The community selected repo maintainers are expected to merge PRs with limited review based on their knowledge of the network operators. Their focus is not to provide editorial oversight but only to:
- prevent updates to a network’s genesis file by other than known operator of the network, and
- prevent badly formatted genesis files from being added to the repository.
The maintainers are authorized to submit PRs to remove “bad actor” network folders based on notifications from the community and followup verification.
§ GitHub Update Disputes
Any disputes about the handling of PRs submitted to the repo should be escalated through the Indy Community (via the #indy channel on Hyperledger chat and/or at the Indy Contributors call or its successor). If the issue is not resolved at the Indy level, the issue should be escalated to Hyperledger leadership (the Executive Director or the Technical Steering Committee).
§ DID Operations
§ Creation
Creation of a did:indy
DID is performed by an authorized entity executing a NYM
ledger transaction on a given Indy network. An Indy NYM transaction includes an identifier (dest
), an ED25519 verification key (verkey
), an optional JSON item (diddocContent
), and an optional NYM transaction version
. The NYM is written to a specific Indy network with a given namespace
. The following validation MUST be performed prior to executing the transaction to create the DID:
-
Based on the configured authorization rules of the specific Indy ledger, the transaction may have to be signed by others, such as a Trustee or Endorser. If transaction is not authorized, the transaction MUST be rejected and an error returned to the client.
-
The Indy ledger MUST verify the relationship between the namespace identifier component of the DID and the initial public key (verkey) according to the NYM transaction
version
number described below. If the relationship between the data elements fails verification, the transaction MUST be rejected and an error returned to the client. -
The NYM transaction requires that the transaction to be written is signed by the DID controller. The ledger MUST verify the signature using the NYM
verkey
. If the signature can not be validated, the transaction MUST be rejected and an error returned to the client. -
The Indy ledger MUST check that the data in the NYM produces valid JSON and MUST do a limited DIDDoc validation check prior to writing the NYM object to the ledger. Details of the assembly and verification are below. If the DIDDoc validation fails, the transaction MUST be rejected and an error returned to the client.
Although the DIDDoc is returned from the DIDDoc assembly and verification process, the DIDDoc is not used further by the ledger.
Once the validation checks are completed, the NYM transaction is written to the Indy distributed ledger. If the NYM write operation fails, an error is returned to the client.
On successfully writing the transaction to the Indy distributed ledger a success status is returned to the client.
§ NYM Transaction Version
The NYM transaction version
specifies the required level of validation of the relationship between the namespace identifier component of the DID and the initial public key (verkey). This field is optional, but if the NYM transaction version
is provided, it must be set upon creation and cannot be updated. The accepted values are as follows:
- 0 or NYM transaction
version
is not set: No validation of namespace identifier and initial verkey binding is performed. - 1: Validation is performed according to the
did:sov
method, in which the DID must be the first 16 bytes of the Verification Method public key. - 2: Validation is performed according to the
did:indy
, in which the namespace identifier component of the DID (last element) is derived from the initial public key of the DID, using the base58 encoding of the first 16 bytes of the SHA256 of the Verification Method public key (did = Base58(Truncate_msb(16(SHA256(publicKey))))
). This DID is considered self-certifying.
The NYM transaction version
is distinct from the DID version described below, which allows for resolution of DIDs at the specified versionId
or versionTime
.
§ Backwards Compatibility
Prior to did:indy
, the unenforced convention in the Indy SDK was to use the following to demonstrate the relationship between the DID and its initial verkey: For an Ed25519 key: Convert into Base58char the first 16 bytes of the 256 bit public key (verkey).
If the did:indy
approach to verifying the relationship between the DID and its initial verkey fail, a client resolving a DID MAY attempt to verify the relationship using the old Indy SDK convention.
When using the old Indy SDK convention of using the first 16 bytes of the verkey, related convention allowed for the placement of a shortened verkey (prefixed with ~
) in the NYM verkey
field, such that the full verkey was dynamically generated by combining the DID and shortened verkey. That convention is NOT used in “did:indy”, but client resolvers using DIDs created prior to did:indy
MUST detect and convert shortened verkeys to full verkeys as necessary.
§ DIDDoc Assembly and Verification
The DIDDoc returned when a did:indy
DID is resolved is not directly stored in an Indy ledger document. Instead, the DIDDoc must be assembled from data elements in the Indy NYM
object based on a series of steps. When a NYM is created or updated the ledger MUST assemble the DIDDoc (following the steps) and validate the DIDDoc. As well, an Indy DID resolver will receive the NYM from the ledger and the non-validation steps must be followed to assemble the DIDDoc for the resolved DID.
The diddocContent
item is stored directly in the ledger state and has a maximum size of 10 KiB (10 x 1024 bytes). If the diddocContent
item contains a @context
item, the resulting DIDDoc is considered JSON-LD. It is the responsibility of the content creator to ensure that it is valid JSON-LD.
§ DIDDoc Validation
The following validation must be performed on a DIDDoc:
- Content must not include
id
at root of the object - Content must not include any nested objects with an
id
ending in <nym>#verkey
This minimal validation allows for the evolution of the DIDDoc without the effort of updating deployments with each minor update. Instead, the writers and resolvers must ensure that the DIDDoc is valid beyond these basic requirements.
§ DIDDoc Assembly Steps
The following are the steps for assembling a DIDDoc from its inputs.
- If the
verkey
isnull
the DID has been deactivated, and no DIDDoc is created. Assembly is complete; return a success status. - The Indy network instance
namespace
, the NYMdest
and the NYMverkey
items are merged into a text template to produce a base DIDDoc.- See the template in the Base DIDDoc Template section of this document.
- If there is no
diddocContent
item in the NYM, assembly is complete; return the DIDDoc and a success status.
- If the
diddocContent
item is included in the NYM, it is verified and merged into the DIDDoc.- The
diddocContent
item MUST NOT have anid
item. If found, exit the assembly process, returning an error. - The
diddocContent
MUST NOT contain an item with the sameid
values as those from the NYM-generated DIDDoc. If a matchingid
is found, exit and return an error. - If the
diddocContent
item containsverificationMethod
and/orauthentication
items, these MUST be arrays. Merge the entries into the respective arrays of the DIDDoc. - Add the other items of the
diddocContent
to the DIDDoc.
- The
- The resulting DIDDoc text must be valid JSON. If not JSON, exit and return an error.
- The resulting JSON must be a valid DIDDoc. Perform the DIDDoc Validation process. If not a DIDDoc, exit and return an error.
- Return the DIDDoc and a success status.
The remainder of this section goes through examples of base DIDDoc template (step 2, above) that is created prior to processing the optional diddocContent
item, and an example of processing a diddocContent
item.
§ Base DIDDoc Template
The base DIDDoc template is static text that forms a JSON structure. To transform a NYM to its minimal DIDDoc, the Indy network instance’s namespace
, and the NYM values dest
and verkey
are inserted into the template as indicated below.
{
"id": "did:indy:<namespace>:<dest>",
"verificationMethod": [{
"id": "did:indy:<namespace>:<dest>#verkey",
"type": "Ed25519VerificationKey2018",
"publicKeyBase58": "<verkey>",
"controller": "did:indy:<namespace>:<dest>"
}
],
"authentication": [
"did:indy:<namespace>:<dest>#verkey"
]
}
Assuming values sovrin
for the namespace
, 123456
for dest
and 789abc
for the verkey
the resulting JSON DIDDoc would be:
{
"id": "did:indy:sovrin:123456",
"verificationMethod": [{
"id": "did:indy:sovrin:123456#verkey",
"type": "Ed25519VerificationKey2018",
"publicKeyBase58": "789abc",
"controller": "did:indy:sovrin:123456"
}
],
"authentication": [
"did:indy:sovrin:123456#verkey"
]
}
§ Example Extended DIDDoc Item
An example of a NYM's extended DIDDoc handling is provided below. In the example below, the diddocContent
item adds a DIDcomm service endpoint to the resolved DIDDoc. Note that in the example, an @context
item is included in the diddocContent
, which causes the result DIDDoc to be a JSON-LD document, rather than plain JSON.
"diddocContent" : {
"@context" : [
"https://www.w3.org/ns/did/v1",
"https://identity.foundation/didcomm-messaging/service-endpoint/v1"
],
"service": [
{
"id": "did:indy:sovrin:123456#did-communication",
"type": "did-communication",
"priority": 0,
"serviceEndpoint": "https://example.com",
"recipientKeys": [ "#verkey" ],
"routingKeys": [ ]
}
]
}
Applying the DIDDoc assembly rules to the example above, the following assembled DIDDoc is produced (it is the responsibility of the content creator to ensure that the DIDDoc is valid JSON-LD):
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://identity.foundation/didcomm-messaging/service-endpoint/v1"
],
"id": "did:indy:sovrin:123456",
"verificationMethod": [{
"id": "did:indy:sovrin:123456#verkey",
"type": "Ed25519VerificationKey2018",
"publicKeyBase58": "789abc",
"controller": "did:indy:sovrin:123456"
}
],
"authentication": [
"did:indy:sovrin:123456#verkey"
],
"service": [
{
"id": "did:indy:sovrin:123456#did-communication",
"type": "did-communication",
"priority": 0,
"serviceEndpoint": "https://example.com",
"recipientKeys": [ "#verkey" ],
"routingKeys": [ ]
}
]
}
§ Key Agreement
By default there is no key agreement section in an assembled DIDDoc. If the DID Controller wants a key agreement key in the DIDDoc, they must explicitly add it by including it in the diddocContent
. For an ED25519 verification key, an X25519 key agreement key could be derived from the verkey (by the client), or a new key agreement key can be generated and used.
§ The “endpoint” ATTRIB
Prior to the definition of this DID Method, a convention on Indy ledgers to associate an endpoint to a NYM involved adding an ATTRIB ledger object with a raw
value of contain the JSON for a name-value pair of endpoint
and a URL endpoint, often an IP address.
We strongly encourage anyone using the “ATTRIB endpoint
” convention to update their NYM on the ledger to use the diddocContent
item as soon as possible, as the ATTRIB is deprecated with the introduction of the did:indy
DID Method.
If a client retrieves a NYM that has a diddocContent
data element, the client should assume that the DID Controller has made the ATTRIB (if any) obsolete and the client SHOULD NOT retrieve the ATTRIB associated with the DID.
If clients want to continue to retrieve and use the endpoint
ATTRIB transaction associated with a NYM, we recommend that the endpoint value (along with namespace
and dest
) be used as if the following was the diddocContent
item in the NYM.
"diddocContent" : {
"@context" : [ "https://identity.foundation/didcomm-messaging/service-endpoint/v1" ],
"service": [
{
"id": "did:indy:sovrin:123456#did-communication",
"type": "did-communication",
"priority": 0,
"serviceEndpoint": "https://example.com",
"recipientKeys": [ "#verkey" ],
"routingKeys": [ ]
}
]
}
The DIDDoc produced by the NYM and “endpoint” ATTRIB would be created using the DIDDoc Assembly Rules and using the diddocContent
from the ATTRIB instead of the NYM item.
§ The “diddocContent” ATTRIB
As described in previous sections, this DID Method introduces the optional diddocContent
item in NYM transactions, which is used in the DIDDoc assembly process.
There may however be networks which use a version of Hyperledger Indy that doesn’t support this field yet. In this case, when creating or updating a did:indy
DID, implementations MAY write the diddocContent
to an ATTRIB transaction with a raw
value containing the JSON for a name-value pair with name diddocContent
, instead of using the field in a NYM transaction.
Once such a network is upgraded to a version that supports the diddocContent
item in the NYM, we strongly encourage anyone using the “ATTRIB diddocContent
” convention to update their NYM on the ledger to use the diddocContent
item as soon as possible, analogous to the “ATTRIB endpoint
” convention.
If a client retrieves a NYM that has a diddocContent
data element, the client should assume that the DID Controller has made the ATTRIB (if any) obsolete and the client SHOULD NOT retrieve the ATTRIB associated with the DID.
Otherwise, the client SHOULD attempt to retrieve the diddocContent
ATTRIB transaction associated with a NYM and, if present, treat it as if its raw
value was the value of the diddocContent
item in the NYM.
The following is an example ATTRIB transaction with a raw
value containing diddocContent
:
{
"txn": {
"data": {
"dest": "P8xKoMHo5tvaCBu9sg7qmE",
"raw": "{\"diddocContent\":{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://identity.foundation/didcomm-messaging/service-endpoint/v1\"],\"service\":[{\"id\":\"did:indy:sovrin:123456#did-communication\",\"type\":\"did-communication\",\"priority\":0,\"serviceEndpoint\":\"https://example.com\",\"recipientKeys\":[\"#verkey\"],\"routingKeys\":[]}]}}"
},
"metadata": {
"reqId": 1681588180411147000,
"from": "P8xKoMHo5tvaCBu9sg7qmE",
"digest": "38f422258c5f674f60e08274cf400a351dabfb3f5c80b59966f2889947bf3387",
"payloadDigest": "0aa1a7d1de92da1056c7702dee10fba0cc7d13378f6cd11ec392da2d95c3e2fb"
},
"protocolVersion": 2,
"type": "100"
},
"txnMetadata": {
"seqNo": 807,
"txnId": "P8xKoMHo5tvaCBu9sg7qmE:1:9bc57c8357576385437819bd163d4cd6dda6acb9a424033d50a646bc54438ef3",
"txnTime": 1681588183
}
}
§ Update
Updating a DID using the Indy DID Method occurs when a NYM
transaction is performed by the NYM's controller (the “owner” of the NYM) using the same identifier (dest
). The Indy ledger MUST validate the NYM transaction prior to writing the NYM to the ledger.
When a NYM is updated, the identifier (dest
) for the NYM does not change, but other values, including the verkey
and diddocContent
, may be changed. This means that (as expected) the DID itself does not change, but the DIDDoc returned by the DID may change. The NYM transaction version
must not be updated.
The following validation steps are performed prior to the update being written to the ledger:
-
Based on the configured authorization rules of the specific Indy ledger, the transaction may have to be signed by others, such as a Trustee or Endorser. If transaction is not authorized, the transaction MUST be rejected and an error returned to the client.
-
The NYM transaction requires that the transaction to be written is signed by the DID controller using the existing
verkey
. The ledger MUST verify the DID controller’s signature. If the DID controller’s signature cannot be validated, the transaction MUST be rejected and an error returned to the client. -
The Indy ledger MUST check that the data in the NYM produces valid JSON and MUST do a limited DIDDoc validation check prior to writing the NYM object to the ledger. Details of the assembly and verification are here. If the DIDDoc validation fails, the transaction MUST be rejected and an error returned to the client.
-
The Indy ledger checks that the NYM transaction
version
is not updated. If theversion
is updated, the transaction MUST be rejected and an error returned to the client.
Although the DIDDoc is returned from the DIDDoc assembly and verification process, the DIDDoc is not used further by the ledger.
Once the validation checks are completed, the NYM update transaction is written to the Indy distributed ledger. If the NYM write operation fails, an error MUST be returned to the client.
On successfully writing the update transaction to the Indy distributed ledger a success status is returned to the client.
§ Read
Reading (resolving) a did:indy
DID requires finding and connecting to the Indy ledger instance holding the DID, retrieving the NYM associated with the DID, verifying the state proof for the returned NYM, and then assembling the DIDDoc. A client/resolver must perform the following steps to complete the process.
- Given a
did:indy
DID, extract the<namespace>
component of the DID. - If the namespace (specific Indy instance) is known to the resolver and the resolver is connected to the ledger continue. If not:
- To read the DIDDoc, the client must get the genesis file for the Indy instance and connect to the ledger. For example, the guidance in the finding Indy ledgers can be used to discover previously unknown Indy ledgers.
- If the client cannot find the Indy network terminate the process and return a “Not Found” status to the caller.
- If the client chooses not to connect to the Indy network terminate the process and return a “Not Authorized” status to the caller.
- Once connected, the
GET_NYM
Indy request is used, passing in the<namespace identifier>
component.- If resolving a prior version of the DID, a different call is used in at this point. See the DID Versions section of this document (below) for more details.
- If the call fails, terminate the process and return a “Not Found” status to the caller.
- If a NYM is returned, use the state proof to verify the result. If the verification fails, terminate the process and return a “Not Found” status to the caller.
- Use the DID
<namespace>
component, the NYM data itemsdest
,verkey
, and (optional)diddocContent
to assemble the DIDDoc using the DIDDoc assembly process defined earlier in this document.- Since the assembly validation was done by the ledger before writing the document, the process should be successful.
- If the DIDDoc is empty (because the
verkey
is null) return a “Not Found” result, otherwise, return the DIDDoc.
§ DID Versions
In resolving a did:indy
DID, the DID resolution query parameters versionId
and versionTime
may be used. When used, process to retrieve the NYM from the ledger (step 3 above) is different.
If the parameter versionId
is used, the value must be an Indy ledger seqno
for the requested NYM on the queried Indy ledger. Instead of using the GET_NYM
call, the Indy GET_TXN
call is used, passing in the seqno
. The result is checked that it is the NYM matching the DID namespace identifier. If so the call is considered to have failed. Either way, the process continues at Step 4.
If the parameter versionTime
is used, the GET_NYM
transaction is called with the appropriate versionTime
timestamp as an additional parameter. The versionTime
parameter MUST be a XML datetime, as defined in the DID Core specification, and will be converted into a POSIX timestamp by the resolver. The Indy ledger code tries to find the instance of the requested NYM that was active at that time (using ledger transaction timestamps) and returns it (if found) or the call fails. Either way, the process continues at Step 4.
§ Deactivate
Deactivation of a did:indy
DID is done by setting the NYM verkey to null. Once done, the DIDDoc is not found (per
the DIDDoc Assembly Steps) and the NYM cannot be updated again.
§ did:indy
DID Component Syntax
The following sections provide the syntax and ABNF for the two variable components of a did:indy
DID, the namespace and namespace identifier.
§ did:indy
DID Namespace Syntax
The did:indy
DID Namespace component MUST include a primary, human-friendly name of the Indy network instance, MAY include an optional “:” separator and subspace, human-friendly name, and MUST include a trailing “:” separator. The subspace name is used to identify an Indy instance related to the primary instance, such as the primary network’s test or development instance. The ABNF for the namespace component is:
namespace = namestring (":" namestring) ":"
namestring = lowercase *(lowercase / DIGIT / "_" / "-")
lowercase = %x61-7A ; a-z
The namespace is set by the operator of the network. Although that could lead to namespace collisions, our assumption about the expected number of Indy instances (low 100s at the most) eliminates that as a concern.
§ did:indy
DID Namespace Identifier Syntax
The namespace identifer is an identifier within the namespace of a Hyperledger Indy network that is unique for that namespace.
The namespace identifier (NSID) is defined by the following ABNF:
NSIDstring = 21*22(base58char)
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"
The NSIDString
is base58 encoded using the Bitcoin/IPFS alphabets of a 16-byte uuid. The encoding uses most alphas and digits, omitting 0 / O / I / l to avoid readability problems. This gives a NSID length of either 21 or 22 characters, and it means that identifiers are case-sensitive and may not be case-normalized, even though the prefix is always lower-case.
The namespace identifier MUST be derived from the initial verkey
for the DID, as outlined in the Creation section of this document.
§ JSON or JSON-LD
The choice of whether a DID resolves to a JSON or JSON-LD document is up to the DID Controller. If the NYM object on the ledger for the DID has a diddocContent
data item, and that data item contains an @context
item, the DIDDoc will be JSON-LD. Otherwise, the resolved DIDDoc will be JSON.
The Indy ledger does not validate the JSON-LD on writing a NYM object to the ledger. It is the responsibility of the DID Controller to ensure that a JSON-LD DIDDoc is valid JSON-LD.
§ Security Considerations
Hyperledger Indy is a public, permissioned distributed ledger that uses RBFT to establish a consensus between upfront well-authenticated nodes. The security mechanisms by indy-node and indy-plenum guarantee the correct processing of requests and transactions according to the rules, which are themselves part of the consensus on the ledger. In particular, this enables the creation and update of schemas, credential definitions and DIDs by their owners by authenticating with the corresponding public keys stored on the ledger.
Hyperledger uses CurveZMQ to secure the communication between the ledger nodes and the clients as well as between the ledger nodes for the consensus. CurveZMQ is an adaptation of the low-level, TCP-based ZMQ communication protocol using the CurveCP to protect the communication layer. CurveCP was designed by Daniel J. Bernstein and uses the 256-bit Curve25519 and derived short-term session keys.
Hyperledger Indy uses a genesis file to securely authenticate the (initial) trusted nodes. This genesis file specifically includes the IP addresses and the long-term keys of the ledger nodes, as well as the DIDs and verification keys of the Trustees and Stewards. The ledger is initially started in a launch ceremony, where all th ledger nodes simultaneously start the indy-node software and ensure the correct startup. The information in the genesis file is sufficient for each client to securely connect to the ledger and gain trust in the transactions provided by the nodes.
The following sections describe how the did:indy
DID Method adheres to the security considerations outlined in the DID Core 1.0 specification and in accordance with RFC3552.
§ Eavesdropping
The CurveZMQ protocol provides confidentiality and integrity by encrypting and authenticating each packet.
§ Replay
The CurveZQM protocol provides protection against replay attacks by including a unique nonce. An attacker cannot replay any packet except a Hello packet, which has no impact on the server or client. Any other replayed packet will be discarded by its recipient. Additionally, the replies for read requests include a timestamp of the state proof of the consensus, therefore the client can check the freshness of the received data.
§ Message Insertion and Modification
The CurveZMQ protocol prevents malicious message insertion as all packets are authenticated and therefore protected against any form of forgery. For write requests, the client signs the sensitive request content with his verification key to authenticate and therefore protect the data against malicious manipulation. Additionally, the consensus prevents forgery of the data returned from the ledger. The stateProof is a multi-signed root hash of a merkle tree that includes all the ledger objects and is part of the node’s reply.
§ Man-In-The-Middle
The client knows the long-term public keys of the ledger nodes from the trusted genesis file. The CurveZMQ protocol protects a Man-In-The-Middle that tries to impersonate the server (ledger node). CurveCP does not protect server from an attacker impersonating the client, as no client authentication is performed on the transport layer. However, the client authenticates on the application layer with by signatures with verification key for the sensitive write requests. Man-in-the-Middle attacks for the inter-node communication is also impossible, as both parties know each others long term public key.
§ Deletion
Deletion of individual messages is not a security risk, as all both every request is answered with a signed response, therefore the lack of response will let the requesting party acknowledge the possible deletion of its message.
§ Denial of Service
Several measures for protection against Denial of Service are taken into account for the indy ledger ecosystem:
- CurveCP uses high-speed high-security elliptic-curve cryptography so that a typical CPU can perform public-key operations faster than a typical Internet connection can ask for those operations. The server does not allocate memory until a client sends the Initiate packet.
- Separate network interfaces to prevent loss of node-to-node communications are advised
- For read requests communication to only one ledger node is necessary to get authentic ledger data as indy uses multi-signed state proofs
§ Storage or Network amplification
Amplification attacks to exhaust the storage of the ledger nodes can be easily mitigated, as only permissioned DIDs have write access and in case of massive malicious requests, these endorsement rights can be revoked.
Amplification attacks to exhaust the network bandwidth are protected to measures similar to section Denial of Service. Additionally, read requests are cheap to process for the ledger node, as the multi-signed state proof is applicable to all requested ledger objects and no new signatures need be calculated except for transport layer security. CurveZMQ is also designed to ensure high efficiency and availability itself.
§ Residual Risks
Residual risks for Hyperledger Indy include:
- compromise in the used cryptographic primitives (BLS-Signature, X25519, Ed25519)
- implementation bugs in the indy-node or indy-plenum software, especially as all nodes use the same software package
- external libraries
§ Integrity protection and update authentication for method operations and write authorization
For all write operations that alter the ledger data(Create, Update, Deactivate) the appropriate signatures are needed, where the DIDs and verkey
s of the signatories must be one the ledger. The client signs the body of the write request (txn
), depending on the configured ledger rules, some transactions might require signatures from multiple DIDs. The Indy ledger processes the signed write request and the software enforces the integrity protection by checking the validity of the given signatures and their authorization. No authentication or authorization is required for read requests.
As Indy currently only provides a single verkey
for authentication, this exposes a risk of loss of control if the private key for the DID Controller is lost.
§ Uniqueness of DIDs
DIDs on the Indy ledger have the option to be self-certifying (NYM transaction version
2), derived from the initial verkey
of an Ed25519 key pair, which makes them extremely likely to be unique. Any attempt to write the same DID would only work if the signature matched (e.g. if the seed to create the DID had been lost so the literal same DID was attempted to be written), which would result in no change to the ledger, and goes against assumption of the DID Controller not protecting their seed/private key. If the signatures do not match in the case of a collision of DIDs, the NYM transaction would be rejected. DIDs of NYM transaction version
1 are also very likely to be unique, but a collision is possible. DIDs that have no validation of namespace identifier and initial verkey binding (NYM transaction version
0 or without a NYM transaction version
) have no guarantees on uniqueness. While DIDs can have different levels of validation as determined by the creator (see DID Creation section for details), self-certification of DIDs will be enforced in the future.
§ Endpoint authentication
No endpoint authentication is used other than the trusted node keys from the genesis files.
§ Protection of data
Transaction data on the ledger stored by the nodes is protected for integrity by maintaining cryptographically signed root hashes of the merkle tree, that includes all transactions of the ledger. Data is not protected for integrity as all data is inherently public anyway.
§ Protection of Key Material
The private keys associated with the public keys written to the ledger must be kept secret. Each DID Owner is responsible to store and use his private keys in a secure and sensitive way.
The ledger nodes are operating with the Validator BLS key, which is stored in software on the node. This private key and the seed used for private key generation is sensitive and can be rotated by using the Steward role of the node’s operator. The Trustees and Stewards verkey
s are highly sensitive and must be securely stored (ideally with Two-Factor-Authentication or in hardware) separate from the ledger. Custom ledger rules that require multiple Trustee and/or Steward signatures to change important configuration data of the ledger are strongly advised.
§ Peer-to-Peer Computing resources
The RBFT algorithm was initially designed as a robust Consensus protocol that limits the effect of malicious nodes. However, this requires some computations that limits the efficiency and scalability of the consensus. It ist strongly advised to not increase the number of validator nodes above 25. Hyperledger Indy was designed with very limited number of write requests, but very efficient read requests (only one node needs to be queried). If scalability issues still arise, the concept of Observer nodes can be implemented.
§ New authentication methods
New authentication methods can be added to the DID Document by adding them to the didDocContent
field. However, the only authentication method applicable to the ownership of Indy-related DID (NYM), is the original verkey
.
§ Privacy Considerations
Given that Indy is a publicly readable, immutable ledger, no personally identifiable information, including DIDs where a person is the DID Subject, should be placed on the network. As this DID method does not offer yet any means to delete or deactivate personal information (e.g. in the sense of GDPR), it is important to enforce these rules by organizational means, for example through an Endorser Transaction Agreement or other contractual agreements.
The further privacy properties are stated according to Section 5 of RFC6973.
§ Surveillance
The DIDs and their resolved DID Documents are public readable and therefore the content and the changes of the data are inherently suspectable to surveillance. Furthermore, authors of read and write requests can be surveilled by their communication to the ledger nodes. Clients sending write requests can be observed and identified by their author DIDs and signatures. However, read requests are unsigned and only need to be sent to one node, therefore offering choice and better protection from surveillance for the client.
§ Stored Data Compromise
The compromise of stored data on the ledger is prevented by the distributed, signed and consensus-based storage of the data. The stored data of an individual ledger node shall be protected by implementing best practice in securing the IT infrastructure, like ISO27001 and Information Security Management systems (ISMS).
§ Unsolicited Traffic
DID Documents can be resolved from a DID, however the DID subject can choose to include or exclude service endpoints that expose itself to unsolicited traffic. The nodes of the ledger itself are exposed to any unwanted traffic as explained in the Denial-of-Service section.
§ Misattribution
DIDs of NYM transaction version
2 are self-certifying and immutable, the control flow of the ledger nodes prevents any misattribution given that it is implemented correctly. It is the responsibility the creator of the DIDs to elect to use the self-certification feature.
§ Correlation
The Hyperledger Indy ecosystem with Anoncreds 1 was designed to prevent correlation by design. No DIDs nor any data or credentials of natural persons are stored on the ledger, the revocation system guarantees a high degree of anonymity. However, DIDs on the ledger, used by organizations, enable correlation by the pseudonymous DID itself or through data like service endpoints from the resolved DID Document as described in the DID-Core specification. Ledger nodes are prohibited to collect any metadata of (read) requests to the ledger to prevent correlation.
§ Identification
The Hyperledger Indy ecosystem prevents identification of natural persons as they do not have a DID on the ledger. Identification of DIDs through the data of the resolved DID Document is possible and usually desired as issuing or verifying organizations want to authentically disclose their identity.
§ Secondary Use
As all data written to the ledger is inherently public, clients sending write requests should be aware of possible secondary use and cautiously decide whether data appropriate data is published. No personal data shall be send to the ledger.
§ Disclosure
Disclosure of data send to the ledger is not an issue, as written data is public anyway. Ledger nodes are prohibited to collect any metadata of (read) requests to the ledger to prevent disclosure.
§ Exclusion
Any read request to the ledger nodes in unauthorized preventing exclusion to the ledger data.
§ Future Directions
§ Multiple Signature NYMs
While not part of this version of the Indy DID Method specification, the group defining the specification recommends that the Indy NYM
be extended to support multiple signature scenarios, where the NYM can be updated to include multiple verification keys, and ledger rules defined for authentication of update transactions, such as M signatures of N total signatures are required. Such a change would be reflected in the verificationMethod
and authentication
items in the generated DIDDoc.
§ Recovery Mechanism
While not part of this version of the Indy DID Method specification, the group defining the specification recommends that the Indy NYM
be extended to support a recovery mechanism, such as defined in KERI. To summarize, a recovery mechanism involves the controller creating not only a verification key pair, but also a recovery public/private key pair during create and update operations. The recovery key is added in some form to (in the case of Indy) the NYM. With a recovery mechanism in place, if only the active key becomes compromised, only the controller can rotate to the recovery key. Assuming the recovery private key is maintained in an even more secure location than the active private key, recovery should always be possible. Without a recovery mechanism, a compromised active key can be used to rotate the verification key and take control of the NYM (and DID) from the controller.
§ KERI Support
Some consideration was given in designing the initial version of the did:indy
DID method to including support for supporting KERI identifiers as part of the DID method. At the time of completing the initial version of the spec there was not a clear definition of what “support” would mean, and the concept was moved to this section of the specification.
§ Cross Registering Indy Ledgers
Some consideration was given to the idea of allowing network discovery by registering network configuration data (such as Indy genesis files) for a ledger on other ledgers. With such a capability with Indy, connecting to one ledger would allow the discovery of all other Indy ledgers registered on that ledger. The idea was partially explored in this document, but the design was not completed in time for inclusion.
§ Other Signature Schemes
Indy implicitly uses the ED25519 Signature scheme for the verkey
. We recommend that the NYMs be evolved to explicitly state the signature scheme so that other signature key schemes can be used on Indy networks.