Product Docs
Product DocsTechnical DocsLearning & GovernanceUseful Links
  • Product Docs
  • Node Docs
  • Learning Docs
  • â„šī¸Getting Started
    • Product Overview
    • âžĄī¸Get Started with cheqd Studio
      • 👉Set Up Your Account
      • đŸ—ī¸Create API Keys
      • đŸĒ™Token Top Up
      • 🔄Advanced Configuration Options
    • â˜‘ī¸Use Trust Registries for AI Agents
      • đŸ—ī¸Build an AI Agent Trust Registry
        • Setup AI Agent Trust Registry
          • Issue Verifiable Credentials to AI Agent
        • Setup and Configure MCP Server
          • Create AI Agent DID
          • Import Credential to AI Agent
          • Advanced functionality
            • Issue a Verifiable Credential
            • Verify a Credential
      • 🤝Validate AI Agent Trust Chain
  • đŸŸĸStart using cheqd
    • 🆔Create DIDs and Identity Keys
      • Create Issuer DID
      • Create Identity Keys and Subject DIDs
      • Resolve a DID
      • Update a DID
      • Deactivate a DID
    • ✅Issue Credentials and Presentations
      • Issue Credential
      • Setup Verida Wallet
      • Verify Credential
      • Verify Presentation
      • Revoke Credential
      • Suspend or Unsuspend Credential
    • â™ģī¸Charge for Verifiable Credentials
      • Understanding Credential Payments
        • Access Control Conditions
        • Privacy Considerations
      • Charge for Status List
      • Issue Credential with Encrypted Status List
      • Create Verifier Pays Issuer flow
      • Bulk Update or Rotate Encryption Keys
    • 🤝Build Trust Registries
      • Decentralized Trust Chains (DTCs)
        • Root Authorisations
        • RTAO -> TAO
        • TAO -> SubTAO
        • TAO -> Trusted Issuer (TI)
        • Referencing Trust Registry within a Verifiable Credential
      • Set up Trust Chain
        • Issue Verifiable Accreditation
        • Verify Verifiable Accreditation
      • Get Started with TRAIN
        • Deploy TRAIN and Anchor rTAO in DNS
        • Validate Trust Chain
    • 🎋Create Status Lists
      • Bitstring Status List
        • Create Bitstring Status List
        • Update Bitstring Status List
        • Check Bitstring Status List
        • Search Bitstring Status List
      • Token Status List
        • Create Token Status List
        • Update Token Status List
    • â†•ī¸Create DID-Linked Resources
      • Understanding DID-Linked Resources
        • Context for developing DID-Linked Resources
        • Technical composition of DID-Linked Resources
        • Referencing DID-Linked Resources in VCs
      • Create DID-Linked Resource
      • Search DID-Linked Resource
  • đŸ› ī¸Integrate an SDK
    • Choosing the right SDK
    • 🍏Credo
      • Setup Credo Agent
      • Decentralized Identifiers (DIDs)
        • Create a DID
        • Update a DID
        • Deactivate a DID
      • DID-Linked Resources
        • Create DID-Linked Resource
        • Resolve DID-Linked Resource
        • Create AnonCreds Schema
        • Create AnonCreds Credential Definition
      • Verifiable Credentials and Presentations
        • Issue a Verifiable Credential (AnonCreds)
        • Present a Verifiable Credential (AnonCreds)
    • 🍊ACA-Py
      • Setup ACA-Py Agent
      • Decentralized Identifiers (DIDs)
        • Create a DID
        • Update a DID
        • Deactivate a DID
      • DID-Linked Resources
        • Create AnonCreds Schema
        • Create AnonCreds Credential Definition
      • Verifiable Credentials and Presentations
        • Issue a Verifiable Credential
        • Present a Verifiable Credential
        • Revoke a Verifiable Credential
    • 🍈Veramo
      • Setup Veramo CLI for cheqd
        • Troubleshooting Veramo CLI setup
      • Decentralised Identifiers (DIDs)
        • Create a DID
        • Querying a DID
        • Update an existing DID
        • Deactivate a DID
        • Create an off-ledger holder DID
        • Managing Identity Keys
        • Troubleshooting
      • Verifiable Credentials and Presentations
        • Issue a Verifiable Credential
        • Verify a Verifiable Credential
        • Create a Verifiable Presentation
        • Verify a Verifiable Presentation
      • Credential Payments
        • Charge for Status List
        • Issue Credential with Encrypted Status List
        • Verifier pays Issuer
      • Bitstring Status List
        • Create Status List
        • Issuing a Verifiable Credential referencing Status List
      • DID-Linked Resources
        • Create a DID-Linked Resource
        • Create a new Resource version within existing Collection
    • đŸĢWalt.id Community Stack
  • đŸ—ī¸Architecture
    • Architecture Decision Record (ADR) Process
    • List of ADRs
      • đŸ”ĩADR 001: cheqd DID Method
      • đŸŸĸADR 002: DID-Linked Resources
      • 🟡ADR 003: DID Resolver
      • 🟠ADR 004: DID Registrar
      • đŸŸŖADR 005: DID Resolution & DID URL Dereferencing
  • đŸ’ĢAdvanced features and alternatives
    • âžĄī¸DID Registrar
      • Setup DID Registrar
      • Create a DID
      • Create a DID-Linked Resource
    • âŦ…ī¸DID Resolver
      • Setup DID Resolver
    • ⚡AnonCreds Object Method
      • Schemas
      • Credential Definitions
      • Revocation Registry Definitions
      • Revocation Status Lists
    • 🌠Advanced Tooling
      • cheqd Cosmos CLI for identity
        • Create a DID
        • Update a DID
        • Deactivate a DID
        • Query a DID
        • Create a DID-Linked Resource
        • Update a DID-Linked Resource
      • Direct interaction with ledger code
      • VDR Tools CLI with cheqd (deprecated)
      • Demo Wallet for Identity Setup
  • âš›ī¸Network
    • Get started with cheqd Network
      • Identity Write Pricing
      • Comparison to Hyperledger Indy
    • ⏊Setup your Wallet
      • Setup Leap Wallet
        • Congifure cheqd testnet for Leap
      • Setup Keplr Wallet
      • Migrate from Keplr to Leap Wallet
    • â†Ēī¸Useful Tools and APIs
      • Block Explorer
      • Testnet Faucet
      • Validator Status API
      • Cheqd x Cosmos Data APIs
      • Cosmos Airdrop Helpers
      • Cosmos Address Convertor
      • Ethereum Bridge
    • âŦ†ī¸Network Upgrades
      • 2021
        • 0.1.x
        • 0.2.x
        • 0.3.x
      • 2022
        • 0.4.x
        • 0.5.x
        • 0.6.x
      • 2023
        • 1.x
      • 2024
        • 2.x
        • 3.x
      • Root Cause Analysis of Outages
        • v1.x upgrade RCA
  • âš–ī¸Legal
    • License
    • Code of Conduct
    • Security Policy
  • 🆘Support
    • System Status
    • Discord
    • Bugs & Feature Requests
Powered by GitBook
LogoLogo

General

  • Website
  • Blog
  • Get $CHEQ

Product Docs

  • Product Docs
  • cheqd Studio
  • Creds.xyz
  • Bug/Feature Requests

Technical Docs

  • Node Docs
  • GitHub
  • Block Explorer

Learning Docs

  • Learning Docs
  • Governance Docs
  • Governance Forum
  • Governance Explorer
On this page
  • Status
  • Summary
  • Context
  • "Resources" in decentralised identity
  • Rationale for storing resources on-ledger
  • Drawbacks of hosting resources on traditional web endpoints
  • Risks applicable in the context of Verifiable Credentials
  • Design principles
  • Resources on cheqd ledger
  • Discoverability via DIDDoc Metadata
  • Resource Preview
  • Optional Discoverability via DIDDoc Services
  • Creating a new Resource within a Resource Collection
  • Resource creation
  • Resource inputs and outputs
  • MsgCreateResource
  • MsgCreateResourceResponse
  • QueryCollectionResourcesRequest
  • QueryCollectionResourcesResponse
  • QueryResourceRequest
  • QueryResourceResponse
  • QueryResourceMetadataRequest
  • State
  • Metadata
  • Data
  • Transactions
  • CreateResource
  • Queries
  • GetCollectionResources
  • GetResource
  • QueryResourceMetadata
  • Resource versioning
  • Decision
  • Assumptions
  • Future improvements
  • Resources module on ledger
  • Dependencies
  • References

Was this helpful?

Edit on GitHub
Export as PDF
  1. Architecture
  2. List of ADRs

ADR 002: DID-Linked Resources

Architecture Decision Record (ADR) detailing cheqd's approach to DID-Linked Resources (DLRs).

Last updated 13 days ago

Was this helpful?

Status

Category
Status

Authors

Ankur Banerjee, Alexandr Kolesov, Alex Tweeddale, Renata Toktar

ADR Stage

ACCEPTED

Implementation Status

Implemented

Start Date

2021-09-23

Last Updated

2023-02-06

Summary

This ADR defines how resources (e.g., text, JSON, images, etc) can be created and referenced using a persistent and unique did:cheqd DID URL.

Each resource will be linked with a DID Document, with create/update operations controlled using the specified verification methods in the associated DID Document.

Context

"Resources" in decentralised identity

In a self-sovereign identity (SSI) ecosystem, resources are often required in tandem with , which is a standard way of representing portable digital credentials that represent claims about its subjects and can be verified via digital proofs.

Common types of resources that might be required to issue and validate Verifiable Credentials are:

  • Schemas: Describe in a machine-readable format. Prominent examples of this include , , etc.

  • Status lists: Allow recipients of a Verifiable Credential exchange to for validity. Prominent examples of this include the specification, , , etc.

  • Visual representations for Verifiable Credentials: Although Verifiable Credentials can be exchanged digitally, in practice most identity wallets want to present "human-friendly" representations. This allows the credential representation to be shown according to the brand guidelines of the issuer, , etc. Examples of this include the , (".pkpass"), , etc.

More broadly, there are other resources that might be relevant for issuers and verifiers in a self-sovereign identity exchange:

Rationale for storing resources on-ledger

Drawbacks of hosting resources on traditional web endpoints

  1. DIDs could be tampered by compromising the hosting provider: DIDs and DID Documents ("DIDDocs") stored at a centralised web endpoint can be compromised and replaced by malicious actors.

  2. Hosting providers could unilaterally cease to host particular clients: Hosting providers could terminate accounts due to factors such as non-payment of fees, violation of Terms of Service, etc.

  3. Single point-of-failure in resiliency: Even for highly-trusted and sophisticated hosting providers who may not present a risk of infrastructure being compromised, a service outage at the hosting provider can make a DID anchored on their systems inaccessible.

Risks applicable in the context of Verifiable Credentials

The issues highlighted above a material difference to the longevity of Verifiable Credentials.

Example schema.org address with full URLs

{
  "@type": "http://schema.org/Person",
  "http://schema.org/address": {
    "@type": "http://schema.org/PostalAddress",
    "http://schema.org/streetAddress": "123 Main St.",
    "http://schema.org/addressLocality": "Blacksburg",
    "http://schema.org/addressRegion": "VA",
    "http://schema.org/postalCode": "24060",
    "http://schema.org/addressCountry": "US"
  }
}

Using traditional web endpoints to store resources (such as schemas) that are critical for a Verifiable Credential to function undermines the benefits that persistently-accessible Decentralized Identifiers offer.

Design principles

We took the following design principles into consideration, along with an explanation of how we addressed them:

  1. Built using existing, familiar DID Core Spec patterns: Wherever possible, our design attempts to utilise existing patterns and behaviours within the W3C DID Core specification (such as the use of DID URLs to identify resources), instead of trying to implement proprietary/custom approaches. We believe that similar designs could be adopted by other DID methods if they choose.

  2. Protection against linkrot for long-term retrieval: Any Resource stored on-ledger is replicated across multiple nodes.

    1. If any individual node or endpoint is down, lookup requests can be sent to any other node on the network.

    2. In a catastrophic scenario where the network itself stops to exist, e.g., companies shutting down, getting acquired etc the on-ledger data can still be restored by digital archivists using ledger snapshots. A practical example of this is how Cosmos Hub makes historical chain archives available which can be restored. While this can be cumbersome, we wanted to design for this as a fail-safe.

  3. Extensible by default: Our objective was to build a flexible design pattern that allowed developers to define and extend their own resource types. Trying to control what kinds of resources could be written to ledger would make the ledger-side logic complex. Instead, we opted for a design where the cheqd ledger acts agnostically to store resources, as long as correctly authorised, as a permanently-accessible endpoint.

  4. Design for DID-spec "dumb" as well as DID-spec "smart" client applications: Many approaches in this space assume that client applications must be adept at parsing DIDDocs and resolving complex inter-DIDDoc relationships. We saw describing resources using DIDDocs as metadata about the resource which could be independently-parsed by "smart" client applications; while also providing a fallback approach for "dumb" client applications. We internally considered this as "What if an identity wallet understood how to parse JSON, but didn't understand the DID Core spec?"

  5. Version controlled: The ability to evolve a resource over time is critical for identity use cases. As described above, examples of this include when identity document schemas change, logos evolve, etc. Current approaches (such as Hyperledger Indy CredDefs) deal with this by creating entirely new, unlinked resources. We designed to make it easy, using existing DID Core specification techniques, so that client applications could query "What was the version of a resource with this name on this date/time?"

Resources on cheqd ledger

Resources on cheqd ledger are collated under Resource Collections, which are defined as a list of resources linked to and controlled using a DID Document ("DIDDoc").

To create a new Resource, a client application first needs to create a DID (or use an existing not deactivated DID along with its associated DIDDoc.) This DID-Linked Resource is the lowest, direct level of create/update/deactivate operation control that exists.

This allows a specific Resource version to be referenced in a Verifiable Credential, as well as allowing client applications to query historical/updated Resource versions along with metadata that describes how the Resource evolved within a Resource Collection.

Discoverability via DIDDoc Metadata

Once a Resource has been created under a Resource Collection, the parent DIDDoc will automatically have an updated didDocumentMetadata section, including linkedResourceMetadata.

The syntax of the linked Resource metadata is as follows:

"didDocumentMetadata": {
    "created": "2020-12-20T19:17:47Z",
    "updated": "",
    "deactivated": false,
    "versionId": "bdab59b0-66f5-42d3-b809-1829bdcc0408",
    "previousVersion": "",
    "nextVersion": "",
    "linkedResourceMetadata": [
      { // First version of a Resource called PassportSchema
        "resourceURI": "did:cheqd:testnet:13d5ad44-9e99-428f-81e9-274458cefddc/resources/44547089-170b-4f5a-bcbc-06e46e0089e4",
        "resourceCollectionId": "13d5ad44-9e99-428f-81e9-274458cefddc", // Common collection ID
        "resourceId": "44547089-170b-4f5a-bcbc-06e46e0089e4", // Old Resource ID and version number
        "resourceName": "PassportSchema", // Resource name must remain the same
        "resourceType": "CL-Schema", // Resource type must remain the same
        "resourceVersion": "1.0.1", // A user-set version
        "mediaType": "application/json",
        "created": "2022-07-19T08:40:00Z",
        "checksum": "7b2022636f6e74656e74223a202274657374206461746122207d0ae3b0c44298", // Old version checksum
        "previousVersionId": "", // empty string, since no previous version
        "nextVersionId": "bb2118f3-5e55-4510-b420-33ef9e1726d2", // Points to next version below
        },
      { // Second version of a Resource called PassportSchema
        "resourceURI": "did:cheqd:testnet:13d5ad44-9e99-428f-81e9-274458cefddc/resources/bb2118f3-5e55-4510-b420-33ef9e1726d2",
        "resourceCollectionId": "DAzMQo4MDMxCjgwM", // Common collection ID
        "resourceId": "bb2118f3-5e55-4510-b420-33ef9e1726d2", // New Resource ID and version number
        "resourceName": "PassportSchema", // Resource name must remain the same
        "resourceType": "CL-Schema", // Resource type must remain the same
        "resourceVersion" "1.0.1" // user-set semantic version control
        "mediaType": "application/json",
        "created": "2022-08-07T08:40:00Z",
        "checksum": "9123dcbb0b42652b0e105956c68d3ca2ff34584f324fa41a29aedd32b883e131", // New version checksum
        "previousVersionId": "44547089-170b-4f5a-bcbc-06e46e0089e4", // Points to previous version above
        "nextVersionId": "0be87654-4a48-4f8e-8789-15ec3589ccdd" // Points to next version. Empty string if no new version
        }
      ]
    }

Importantly, we decided not to populate the actual resource data into the didDocumentMetadata, but instead, what we refer to as a Resource Preview which contains all the metadata about the associated resources.

Resource Preview

Resource previews will aopear within DIDDocMetadata. These do not include the actual core data of the resource and only reference the metadata:

  • Resource Collection ID: (did:cheqd:...:) (supplied client-side)**

  • Resource ID: UUID ➝ specific to resource, also effectively a version number (supplied client-side)

  • Resource Name: String (e.g., CL-Schema1 (supplied client-side))

  • Resource Type (supplied client-side)

  • Resource Version (supplied client-side)

  • MediaType: (e.g. application/json/image/application/octet-stream/text/plain) (computed ledger-side)

  • Created: XMLDatetime (computed ledger-side)

  • Checksum: SHA-256 (computed ledger-side)

  • previousVersionId: empty string if first, otherwise ID as long as Name, ResourceType, and MimeType match previous version (computed ledger-side)

  • nextVersionId: empty string if first/latest, otherwise ID as long as Name, ResourceType, and MimeType match previous version (computed ledger-side)

  • Also known as: a list of alternative URIs that can be used to get the resource.

Example:

{
  "resourceUri": "did:cheqd:testnet:13d5ad44-9e99-428f-81e9-274458cefddc/resources/bb2118f3-5e55-4510-b420-33ef9e1726d2",
  "resourceCollectionId": "13d5ad44-9e99-428f-81e9-274458cefddc",
  "resourceId": "bb2118f3-5e55-4510-b420-33ef9e1726d2",
  "resourceName": "PassportSchema",
  "resourceType": "CL-SChema",
  "resourceVersion": "1.0.1",
  "mediaType": "application/json",
  "created": "2022-04-20T20:19:19Z",
  "checksum": "a7c369ee9da8b25a2d6e93973fa8ca939b75abb6c39799d879a929ebea1adc0a",
  "previousVersionId": "67f2df00-0b6e-404b-8c70-1d63200e6412",
  "nextVersionId": "98922424-c214-4439-b52c-f68ddb450b40",
  "alsoKnownAs": [{
      "uri": "https://example.com/alternative-uri",
      "description": "Alternative URI description"
      },
      {
      "uri": "https://example.com/alternative-uri",
      "description": "Alternative URI description"
      }]
}

Optional Discoverability via DIDDoc Services

The rationale for linking to Resources in this manner, instead of creating a new top-level section, are as follows:

  1. In practice, we noted that client applications capable of DID Resolution will gracefully fail/ignore unknown Service types. Client applications that do understand a particular Service type can continue parsing/resolving content they are designed to handle.

  2. Historical versions of Resources can always be accessed by traversing forwards/backwards in the Resource Collection by checking if a particular Service ID has old/new versions.

  3. Multi-party control on Resource Collection updates is possible, since DIDs with multiple controllers specified in them already handle this scenario. In the normal process of updating a DIDDoc with multiple controllers, rules can be defined by client applications and/or the ledger on whether all controllers sign an update, or whether an m-of-n threshold needs to be applied. (Currently, the cheqd ledger requires all controllers to sign off on updates.)

Example of referencing a resource using the service section:

  {
    "service": [{
      "id":"did:cheqd:testnet:13d5ad44-9e99-428f-81e9-274458cefddc#PassportSchema",
      "type": "LinkedResource",
      "serviceEndpoint": [
        "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:13d5ad44-9e99-428f-81e9-274458cefddc/resources/bb2118f3-5e55-4510-b420-33ef9e1726d2"
      ]
    }]
  }

Creating a new Resource within a Resource Collection

To create a new DID-Linked Resource, a client application first needs to create a DID (or use an existing DID along with its associated DIDDoc). This DID-Linked Resource is the lowest, direct level of create/update/deactivate operation control that exits.

Resource creation

Each request to create a Resource must provide the following parameters, supplied by the client application:

  • Resource Collection ID: (did:cheqd:...:) (supplied client-side)

  • Resource ID: UUID ➝ specific to resource, also effectively a version number (supplied client-side)

  • Resource Name: String (e.g., CL-Schema1 (supplied client-side))

  • Resource Version: String (OPTIONAL). It is a human-readable semantic version for the Resource (e.g., 1.0.0 (supplied client-side))

  • alsoKnownAs: (OPTIONAL) a list of alternative URIs that can be used to get the resource.

In addition to the above client-provided parameters, the ledger-side code will populate the following additional header fields (for properly-authenticated requests):

  • MediaType: (e.g. application/json/image/application/octet-stream/text/plain) (computed ledger-side) This is based on the file extension of the associated resource file.

  • Created: XMLDatetime (computed ledger-side)

  • Checksum: SHA-256 (computed ledger-side)

  • previousVersionId: an empty string if first, otherwise ID as long as Name, ResourceType, and MimeType match previous version (computed ledger-side)

  • nextVersionId: an empty string if first/latest, otherwise ID as long as Name, ResourceType, and MimeType match previous version (computed ledger-side)

Example using the Veramo CLI:

{
    "kms": "local",
    "payload": { // example of resource header
        "collectionId": "13d5ad44-9e99-428f-81e9-274458cefddc",
        "id": "bb2118f3-5e55-4510-b420-33ef9e1726d2",
        "name": "PassportSchema",
        "version": "1.0.1",
        "resourceType": "CL-Schema",
        "alsoKnownAs": [{
            "uri": "https://example.com/alternative-uri",
            "description": "Alternative URI description"
            },
            {
            "uri": "https://example.com/alternative-uri",
            "description": "Alternative URI description"
            }],
        "data": "eyJhdHRyIjpbIm5hbWUiLCJhZ2UiXX0=" // file with resource encoded into base64 or path to file
    },
    "signInfo": [{
        "verificationMethodId": "did:cheqd:testnet:13d5ad44-9e99-428f-81e9-274458cefddc#key-1",
        "signature": "0f5c124886178037952e87e0cdc55d185732577fca19ae877e64ac9ab24a0cc534e5326e70f1a42d785d93048aee806c359ec75a7b06f39253befd1746708438"
    }]
}

Resource inputs and outputs

This section will delineate between expected inputs in JSON and how the cheqd ledger stores the resource input in protobuf

MsgCreateResource

  • collectionId: (did:cheqd:...:)<identifier> (supplied client-side) ➝ unique identifier from DIDDoc.

  • id: UUID representing resource ID ➝ specific to resource, also effectively a version number (supplied client-side)

  • name: String (e.g., CL-Schema1 (supplied client-side))

  • version: String (OPTIONAL) ➝ a human-readable semantic version for the Resource (e.g., 1.0.0 (supplied client-side))

  • data: Bytes representing a user data (supplied client-side)

  • alsoKnownAs (supplied client-side) a list of alternative URIs for the SAME Resource

  • signInputs: Signatures of the corresponding DID Document's controller(s) (supplied client-side).

"Example"
{
    "payload": {
        "data": "eyJhdHRyIjpbIm5hbWUiLCJhZ2UiXX0=",
        "collectionId": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
        "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f",
        "name": "PassportScheme",
        "version": "1.0",
        "resourceType": "CL-Schema",
        "alsoKnownAs": [
            {
                "uri": "https://example.com/alternative-uri",
                "description": ""
            },
            {
                "uri": "https://example.com/alternative-uri",
                "description": "Alternative URI description"
            }
        ]
    },
    "SignInfo": [
        {
            "verificationMethodID": "did:cheqd:testnet:91e5f0cf-5f1e-5c19-97d3-d313e84033b4#key-1",
            "Signature": "m0ZE4x5Qxs+6HEBoXDrjtGTLr9GuXjIttSznoVumRWIA3GMeDipXnCVgdZfa0PUVVdr2DQy9a0NyPXPeQcXdCw=="
        }
    ]
}

MsgCreateResourceResponse

  • Resource is stored on-ledger in protobuf. This is converted back to JSON client side.

"Example"
{
    "resource": {
        "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
        "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f",
        "name": "PassportScheme",
        "version": "1.0",
        "resource_type": "CL-Schema",
        "also_known_as": [
            {
                "uri": "https://example.com/alternative-uri",
                "description": ""
            },
            {
                "uri": "https://example.com/alternative-uri",
                "description": "Alternative URI description"
            }
        ]
    }
}

QueryCollectionResourcesRequest

  • Collection ID: String - an identifier of linked DIDDoc.

"Example"
{ "collectionId": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4" }

QueryCollectionResourcesResponse

  • Returns collection of resources created by the specific collection ID. This is converted to JSON on the client side.

"Example"
{
    "resources": [
        {
            "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
            "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f",
            "name": "TicketSchema",
            "version": "1.0",
            "resource_type": "CL-Schema",
            "also_known_as": [
                {
                    "uri": "https://example.com/alternative-uri",
                    "description": ""
                }
            ],
            "media_type": "application/json",
            "created": "2023-01-21T20:02:55.664985039Z",
            "checksum": "a7cd6c222ea5fc1463c0ca3f70b93035196c8c4f34d89181ff5086bd7b58bfff",
            "previous_version_id": "",
            "next_version_id": ""
        },
        {
            "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
            "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f",
            "name": "PassportSchema",
            "version": "1.0",
            "resource_type": "CL-Schema",
            "also_known_as": [
                {
                    "uri": "https://example.com/alternative-uri",
                    "description": ""
                },
                {
                    "uri": "https://example.com/alternative-uri",
                    "description": "Alternative URI description"
                }
            ],
            "media_type": "application/json",
            "created": "2023-01-21T20:02:55.664985039Z",
            "checksum": "a7cd6c222ea5fc1463c0ca3f70b93035196c8c4f34d89181ff5086bd7b58bfff",
            "previous_version_id": "",
            "next_version_id": ""
        }
    ]
}

QueryResourceRequest

  • Collection ID: String - an identifier of linked DIDDoc

  • ID: String - unique resource id

"Example"
{ 
  "collectionId": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
  "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f"
}

QueryResourceResponse

  • Returns Resource with a given collection ID and ID. This is converted to JSON client side.

"Example"
{
    "resource": {
        "resource": {
            "data": "eyJ0ZXN0IjogInRlc3QifQ=="
        },
        "metadata": {
            "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
            "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f",
            "name": "PassportSchema",
            "version": "1.0",
            "resource_type": "CL-Schema",
            "also_known_as": [
                {
                    "uri": "https://example.com/alternative-uri",
                    "description": ""
                },
                {
                    "uri": "https://example.com/alternative-uri",
                    "description": "Alternative URI description"
                }
            ],
            "media_type": "application/json",
            "created": "2023-01-21T20:02:55.664985039Z",
            "checksum": "a7cd6c222ea5fc1463c0ca3f70b93035196c8c4f34d89181ff5086bd7b58bfff",
            "previous_version_id": "",
            "next_version_id": ""
        }
    }
}

QueryResourceMetadataRequest

  • Collection ID: String - an identifier of linked DIDDoc

  • ID: String - unique resource id

"Example"
{ 
  "collectionId": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
  "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f"
}

QueryResourceMetadataResponse

Returns resource's metadata with a given collection ID and ID.

"Example"
{
    "resource": {
        "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
        "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f",
        "name": "PassportSchema",
        "version": "1.0",
        "resource_type": "CL-Schema",
        "also_known_as": [
            {
                "uri": "https://example.com/alternative-uri",
                "description": ""
            },
            {
                "uri": "https://example.com/alternative-uri",
                "description": "Alternative URI description"
            }
        ],
        "media_type": "application/json",
        "created": "2023-01-21T20:02:55.664985039Z",
        "checksum": "a7cd6c222ea5fc1463c0ca3f70b93035196c8c4f34d89181ff5086bd7b58bfff",
        "previous_version_id": "",
        "next_version_id": ""
    }
}

State

Metadata

  • resources-metadata:<collection-id>:<resource-id> ➝ Metadata

    • <collection-id> is the last part of DID. It can be UUID, Indy-style or whatever is allowed by ledger. It allows us to evolve over time more easily.

    • <resource-id> is a unique resource identifier on UUID format

Data

  • resources-data:<collection-id>:<resource-id> ➝ Data

    • <collection-id> is the last part of DID. It can be UUID, Indy-style or whatever is allowed by ledger. It allows us to evolve over time more easily.

    • <resource-id> is a unique resource identifier on UUID format

Transactions

CreateResource

  • Input:

  • Output:

  • Processing logic:

    • Check that associated DIDDoc exists;

    • Authenticate request the same way as DIDDoc creation and updating;

    • Validate properties;

    • Validate that ID is unique;

    • Set created date time;

    • Set previousVersion and nextVersion if this is a new version (a resource with the same collection-id, resource-name and resource-type exists);

    • Compute checksum;

    • Persist the resource in state;

cheqd Cosmos CLI Example:

cheqd-noded tx resource create [payload-file] [resource-data-file]
  • payload-file: path to the payload file:

{
    "payload": {
        "collectionId": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",
        "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f",
        "name": "PassportSchema",
        "version": "1.0",
        "resourceType": "CL-Schema",
        "alsoKnownAs": [
            {
                "uri": "https://example.com/alternative-uri",
                "description": ""
            },
            {
                "uri": "https://example.com/alternative-uri",
                "description": "Alternative URI description"
            }
        ]
    },
    "signInputs": [
        {
            "verificationMethodID": "did:cheqd:testnet:91e5f0cf-5f1e-5c19-97d3-d313e84033b4#key-1",
            "privKey": "tBjxEJCqSkj7u+iTWRqAVZwtcl2XBZrlaMfhxYIRc4wj7epbmDkJ35sCin3MWnAxvHJNDY0yyPafVspsrgb1Ng=="
        }
    ]
}
  • resource-data-file: path to the resource file (e.g.: /path/to/resource.jpeg)

Queries

GetCollectionResources

  • Input:

  • Output:

  • Processing logic:

    • Retrieves the whole resource collection for the specified DID;

    • Returns only resource headers (without data field);

cheqd Cosmos CLI Example:

cheqd-noded query resource collection-metadata [collection-id]

GetResource

  • Input:

  • Output:

  • Processing logic:

    • Retrieves a specific resource by Collection-ID and resource ID;

cheqd Cosmos CLI Example:

cheqd-noded query resource specific-resource [collectionId] [id]

QueryResourceMetadata

  • Input:

  • Output:

  • Processing logic:

    • Retrieves all resource versions by collection id, resource id

    • Returns a resource's metadata from a collection with a given collection_id and id

cheqd Cosmos CLI Example:

cheqd-noded query resource resource-metadata [collectionId] [id]

Resource versioning

Resource are immutable, but it is possible to create new versions of it under a new identifier(id field). When creating a resource whose fields collection_id, name and resource_type match an existing resource:

  • The latest version of the current resource will be added with a link to the new one. That is, field next_version_id will contain the new resource identifier.

  • A new resource with data from the transaction will be created with the previous version resource id in field previousVersionId.

Example:

Step 1. Resource exists in the ledger:

{
  "resource": {
    "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",  // Common collection ID
    "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f", // Old Resource ID and version number
    "name": "PassportScheme", // Resource name must remain the same
    "version": "1.0", // Resource version
    "resource_type": "CL-Schema", // Resource type must remain the same
    "also_known_as": [
        {
            "uri": "https://example.com/alternative-uri",
            "description": ""
        },
        {
            "uri": "https://example.com/alternative-uri",
            "description": "Alternative URI description"
        }
    ],
    "media_type": "application/json",
    "created": "2022-07-19T08:40:00Z",
    "checksum": "7b2022636f6e74656e74223a202274657374206461746122207d0ae3b0c44298", // Old version checksum
    "previous_version_id": "", // an empty string, since no previous version
    "next_version_id": "" // an empty string, since no next version
  }
}

Step 2. Client send request for creating a new resource with a transaction MsgCreateResource

MsgCreateResource for creating Resource2
{
  "collectionId":   "91e5f0cf-5f1e-5c19-97d3-d313e84033b4", // same collection ID
  "id":             "bb2118f3-5e55-4510-b420-33ef9e1726d2", // new unique ID
  "name":           "PassportSchema", // same resource name
  "resourceType":   "CL-Schema", // same resource type
  
  "data":           ...
}

Step 3. After the transaction is applied

"resources": [
  { // First version of a Resource called PassportSchema
    "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4",  // Common collection ID
    "id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f", // Old Resource ID and version number
    "name": "PassportScheme", // Resource name must remain the same
    "version": "1.0", // Resource version
    "resource_type": "CL-Schema", // Resource type must remain the same
    "also_known_as": [
        {
            "uri": "https://example.com/alternative-uri",
            "description": ""
        },
        {
            "uri": "https://example.com/alternative-uri",
            "description": "Alternative URI description"
        }
    ],
    "media_type": "application/json",
    "created": "2022-07-19T08:40:00Z",
    "checksum": "7b2022636f6e74656e74223a202274657374206461746122207d0ae3b0c44298", // Old version checksum
    "previous_version_id": "", // an empty string, since no previous version
    "next_version_id": "bb2118f3-5e55-4510-b420-33ef9e1726d2", // Points to next version below
  },
  { // Second version of a Resource called PassportSchema
    "collection_id": "91e5f0cf-5f1e-5c19-97d3-d313e84033b4", // Common collection ID
    "id": "bb2118f3-5e55-4510-b420-33ef9e1726d2", // New Resource ID and version number
    "name": "PassportScheme", // Resource name must remain the same
    "version": "1.0", // Resource version
    "resource_type": "CL-Schema", // Resource type must remain the same
    "also_known_as": [
        {
            "uri": "https://example.com/alternative-uri",
            "description": ""
        },
        {
            "uri": "https://example.com/alternative-uri",
            "description": "Alternative URI description"
        }
    ],
    "media_type": "application/json",
    "created": "2022-07-19T08:40:00Z",
    "checksum": "7b2022636f6e74656e74223a202274657374206461746122207d0ae3b0c44298", // Old version checksum
    "previous_version_id": "54cb8b4d-af33-4606-bc54-0f035ee30e0f", // Points to previous version above
    "next_version_id": "" // an empty string, since no next version
  }
]

Decision

Assumptions

  • Immutability:

    • Resources on-ledger are immutable, so can't be destroyed;

  • Limitations

    • Resource size is now limited by maximum tx/block size;

Future improvements

  • Limitations

    • Introduce module level resource size limit that can be changed by voting

Resources module on ledger

A new module will be created: resource.

Dependencies

  • It will have cheqd module as a dependency.

    • Will be used for DIDs existence checks.

    • Will be used for authentication

References

Figure 1: Mobile boarding passes in Apple Wallet showing different visual styles (source

Such visual representations can also be used to quickly communicate information visually during identity exchanges, such as airline mobile boarding passes. In the , the pass at the front is for a "Gold" loyalty status member, whereas the pass at the back is for a "standard" loyalty status member. This information can be represented in a Verifiable Credential, of course, but the example here uses the Apple Wallet / Google Wallet formats to overlay a richer, "human-friendly" display.

Documents related to SSI ecosystems: , which would typically be a text file, a , PDF etc. This, for example, can enable parties building self-sovereign identity ecosystems to use DIDs to reference Governance Frameworks they conform to, at different levels of the technical stack.

Logos: Issuers may want to provide authorised image logos to display in relation to their DID or Verifiable Credentials. Examples of this include (which is used by to show logos for validators) and "" (commonly used to set the logo for websites in browser tabs).

Decentralized Identifiers (DIDs) are often stored on ledgers (e.g., , ), distributed storage (e.g., in ), or non-ledger distributed systems (e.g., ).

DIDs can be stored on traditional centralised-storage endpoints (e.g., , ) but this comes with certain drawbacks:

See from major cloud providers: , , , , , ...\

Source: . Figure 2: Graph showing drop in Facebook traffic from their global service outage in 2021 (source: ).

In particular, also functionality. This highlights the risks of "contagion impact" (e.g., ) of centralised digital systems - even ones run by extremely-capable tech providers.

Link rot: "Link rot" happens when over time, URLs become inaccessible, either because the endpoint where the content was stored is no longer active, or the URL format itself changes. The graph below from shows degradation over time of URLs.

Figure 3: Linkrot analysis over 1996-2019 by New York Times (source: )_

For example, a passport ( issued as a Verifiable Credential anchored to a DID (regardless of whether the DID was on-ledger or not) might stop working if the credential schema, visual presentation format, or other necessary resources were stored off-ledger on traditional centralised storage.

Despite these issues, many self-sovereign identity (SSI) implementations - even ones that use ledgers / distributed systems for DIDs - often utilise centralised storage. From the :

Make re-use of resources simple: We liked the concept of in the sense that it promotes a common, machine-readable specification. Therefore, our design allows for patterns where the controllers of a DID can reference resources created by other DID owners/controllers, e.g., referencing a pre-existing schema. Taking this line of thought further, it allows for an arbitrary depth of how resources can be nested, as long as they are discoverable/resolvable.

Notalltypes of resources should be stored on a ledger...but can be made discoverable through similar design patterns: Distributed ledgers are great for redundancy, but the cost of this duplication (in terms of storage required by node, block size, transaction finality speeds, etc) can be quite significant. For instance, a distributed ledger is probably not the best storage and retrieval mechanism for a video file (which can run into many GBs/TBs); or even a PDF larger than a few MBs. cheqd network . This can be updated via an on-ledger vote, but the trade-off of asking node operators to provision ever-expanding storage would be not ideal. Our design therefore restricts the file/payload size of on-ledger resources (in our case, ~190 KB - giving enough room for transaction data besides the resource itself), while allowing the same techniques below to be used for describing off-ledger resources. E.g., references . We recognise and accept that DID owners/creators may choose to use their own centralised/decentralised storage, and the design patterns described below accommodate that.

Figure 4: Overview of Resource and Resource Collection creation )

Individual Resources are uniquely identified by a common Resource Name and common Resource Type that MUST remain consistent across versions. The specific version number of a Resource is described using the Resource ID, which is a . Since UUIDs can be generated by any compatible software library, client applications are able to define this version number independent of the cheqd ledger. This same technique and rationale is described in .

Once a Resource has been created under a Resource Collection, the linked DIDDoc can be updated to provide a link to access it in the .

Client applications capable of doing may have strong architectural assumptions to only expect the default DID Core specification sections in a response. We considered the possibility that such applications might (incorrectly) reject the entire DIDDoc as malformed, or crash in the process of trying to parse the DIDDoc.

On the other hand, is designed to be flexible and extensible by design. New DID Service types can be registered through by anyone. We suggest a new service type called LinkedResource should be used to reference any resource on cheqd within the service section. This is conceptually similar to the existing .

DIDDocs can reference other DIDDocs, such as when the in one DIDDoc is specified as a Verification Method in another DIDDoc. These links can be traversed using .

Since the , this provides another layer of access control by allowing DIDDoc controllers to rotate keys, if required.

Figure 5: Detailed sequence diagram of Resource creation on cheqd .

Resources must be under the maximum block size restrictions to be able to fit into a transaction. Currently this is plus additional headroom for metadata that needs to be described in the ResourceHeader.

Resource Type: (e.g JSONSchema 2020, supplied client-side. It is recommended that new Resource Types are included in the )

resourceType: a string representing type of resource (supplied client-side). It is recommended that new Resource Types are included in the .

specification

official specification

official project website

GitHub repository ()

official project background on Hyperledger Foundation wiki

GitHub repository: Server-side blockchain node for Indy ()

GitHub repository: Plenum Byzantine Fault Tolerant consensus protocol; used by indy-node ()

(did:indy)

official project background on Hyperledger Foundation wiki

GitHub repository: Provides links to implementations in various programming languages

GitHub repository: Contains Requests for Comment (RFCs) that define the Aries protocol behaviour.

đŸ—ī¸
đŸŸĸ
W3C Verifiable Credentials
the fields and content types in a credential
Schema.org
Hyperledger Indy SCHEMA objects
check the revocation status of a credential
W3C Status List 2021
W3C Revocation List 2020
Hyperledger Indy revocation registries
internationalisation ("i18n") translations
Overlays Capture Architecture (OCA) specification
Apple Wallet PassKit
Google Wallet Pass
British Airways Media centre
example above from British Airways
ToIP recommends making Governance Frameworks available through DID URLs
Markdown file
key-publishing sites like Keybase.io
Cosmos SDK block explorers such as our own
favicons
cheqd
Hyperledger Indy
IPFS
Sidetree
KERI
did:web
did:git
notable examples of service outages
Amazon Web Services (AWS)
Microsoft Azure
Google Cloud
Facebook / Meta
GitHub
Cloudflare
Why Facebook, Instagram, and WhatsApp All Went Down Today
Kentik
the 2021 global Facebook outage
took down apps that used "Login with Facebook"
a different Facebook outage took down Spotify, TikTok, Pinterest
an analysis by The New York Times of linkrot
Columbia Journalism Review / New York Times
which typically have a 5-10 year validity
W3C Verifiable Credential Implementation Guide
Schema.org
restricts the block size for an individual block to ~200 KB
our first DID on cheqd network
a 7+ MB image accessible via IPFS
editable version
Universally-Unique Identifier (UUID)
ADR-001: cheqd DID method
service section
DID Resolution
the Service section in a DIDDoc
DID Specification Registries
LinkedDomains
DID Controller
DID URL dereferencing
cheqd ledger does not co-relate the on-ledger cheqd/Cosmos accounts to keys that control DIDDocs
editable version
estimated to be ~190 KB on cheqd mainnet, based on the ~200 KB block size limit
DID Spec Registries
DID Spec Registries
W3C Decentralized Identifiers (DIDs)
DID Core Specification Test Suite
W3C Verifiable Credentials
Cosmos blockchain framework
cosmos-sdk
documentation
Hyperledger Indy
indy-node
documentation
indy-plenum
documentation
Indy DID method
Indy identity-domain transactions
Hyperledger Aries
aries
aries-rfcs
MsgCreateResource
MsgCreateResourceResponse
QueryCollectionResourcesRequest
QueryCollectionResourcesResponse
QueryResourceRequest
QueryResourceResponse
QueryResourceMetadataRequest
QueryResourceMetadataResponse
Mobile boarding pass
Graph showing drop in Facebook traffic from their global service outage in 2021
Image of Link Rot over time
Swimlanes for Resource creation
Complex swimlanes for resource creation