# Scope Document
## Overview
This document outlines the scope of the upcoming tasks related to the implementation and enhancement of DID:web in ACA-py. The tasks are aimed at improving DID and key management using plugins and ensuring compatibility with anoncreds.
## Tasks
### 1. Support for DID:web in ACA-py
**Objective:**
Implement support for DID:web, allowing decentralized identifiers to be utilized on the web.
**Findings:**
##### Existing state of DID:web compatibility in ACA-py
DID:web has limited compatibility within ACA-py. Some of the APIs support protocols using DID:web (like connections, did resolve), while some provide a partial support for did:web (like credential issuance), and some did not support at all (like proof presentation). A detailed research has been done on the state of did:web compatibility, and APIs for which did:web does not work currently are:
- For JSON-LD credentials
- POST `/present-proof-2.0/records/{pres_ex_id}/send-presentation`
- POST `/present-proof-2.0/records/{pres_ex_id}/verify-presentation`
- For example, the following credential offer is working when issuer is did:web and subject (or holder id) is a did:sov or did:key. Our requirement is to support a did:web based subject (holder id).
```json=
{
"auto_issue": false,
"auto_remove": false,
"comment": "Credential from minimal example",
"connection_id": "df82e639-c15c-4374-8e9a-f820be2a1c6f",
"filter": {
"ld_proof": {
"credential": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/citizenship/v1"
],
"credentialSubject": {
"birthCountry": "Bahamas",
"birthDate": "1958-07-17",
"familyName": "Builder",
"gender": "Male",
"givenName": "Bob",
"id": "did:key:z6MkpSRWLxKgFCkJo8WUmyEdxswsMnZpQzaqFxu6LbtpASPM",
"type": [
"PermanentResident"
]
},
"issuanceDate": "2024-05-24",
"issuer": "did:web:aritra-issuer-faber.nborbit.ca",
"type": [
"VerifiableCredential",
"PermanentResident"
]
},
"options": {
"proofType": "Ed25519Signature2018",
"proofPurpose": "assertionMethod", #
"verificationMethod": "did:web:aritra-issuer-faber.nborbit.ca#key-1" #
}
}
},
"trace": false
}
```
- For Indy/Anoncreds credentials
**Note**: did:web currently does not support Indy/Anoncreds credentials because they heavily rely on the ledger for working and the did:web does not exist on ledger. It is a bigger problem which needs to be addressed as a seperate issue.
- Identification of key challenges and limitations.
For a credential holder who currently does not have a did:sov or did:key id available (which means they are not present in the Indy ledger), it is currently not possible to prove a credential presentation request as the agent cannot retrieve verification method from the did:web.

**Approach:**
1. Conduct a thorough literature review on DID:web.
2. Identify where the problem occurs
- When the `send-presentation` endpoint is called, it build the VP by calling the following functions:
- Function`present_proof_send_presentation` at `aries_cloudagent/protocols/present_proof/v2_0/routes.py`
- `create_pres` at `aries_cloudagent/protocols/present_proof/v2_0/manager.py`
- `create_pres` at `aries_cloudagent/protocols/present_proof/v2_0/formats/dif/handler.py`
- `create_vp` at `aries_cloudagent/protocols/present_proof/dif/pres_exch_handler.py`
- `_get_issue_suite` at `aries_cloudagent/protocols/present_proof/dif/pres_exch_handler.py`
- `get_verification_method_id_for_did` at `aries_cloudagent/wallet/default_verification_key_strategy.py`
4. Develop a prototype implementation.
- Adjust the functions that are causing problem with did:web. As per current observation we need to add a verification key derivation strategy for did:web in the function `default_verification_key_strategy`.
- To do this, we can resolve the did:web using aca-py's `resolve` method, look at the services, and use the verification key for a service which supports DIDComm protocols.
- This we need to do because the function assumes a did:key or did:sov is used as the holder id in the credential subject ID. In other places, where explicit DID is provided it does not create an issue.
4. Test the prototype for interoperability and performance.
- The prototype implementation works for preliminary testing of `did:web` credential issuance and verification flow.
- The unit tests that came with ACA-py also pass.
- The implementation has the performance overhead of a `did:web` resolve call which is essentially dependent on the network of the user.
6. Document the implementation process and findings.
- The implementation involves adding the logic for retirieving verification record for `did:web` in a similiar manner as already implemented in the function.
- This can be done by first checking if the DID is of `did:web` type, and in that case the DID gets resolved into a DID document.
- The DID document is checked for verification methods. It gets the first verification method found in the doc for signing process.
The changes in the code are:
```python=
async def get_verification_method_id_for_did(
self,
did: str,
profile: Optional[Profile],
allowed_verification_method_types: Optional[List[KeyType]] = None,
proof_purpose: Optional[str] = None,
) -> Optional[str]:
"""Given a did:key or did:sov, returns the verification key ID in use.
Returns None if no strategy is specified for this DID.
:params did: the did
:params profile: context of the call
:params allowed_verification_method_types: list of accepted key types
:params proof_purpose: the verkey relationship (assertionMethod, keyAgreement, ..)
:returns Optional[str]: the current verkey ID
"""
if did.startswith("did:key:"):
return DIDKey.from_did(did).key_id
elif did.startswith("did:sov:"):
# key-1 is what uniresolver uses for key id
return did + "#key-1"
elif did.startswith("did:web:"):
did_resolver = profile.inject(DIDResolver)
did_document = await did_resolver.resolve(profile=profile, did=did)
# Get the verification method ID from the DID document
# take first verification method for now
verification_method_list = did_document.get("verificationMethod", {})
verification_method_id = verification_method_list[0].get("id")
return verification_method_id
return None
```
### 2. DID and Agent Separation POC using Plugin
**Objective:**
Separate DID and agent functionalities using a plugin-based approach to enhance modularity and flexibility. Our recommendation is that DID methods like `key`, `sov`, `web`, etc. can support their DID core specification as their own plugin.
**Findings:**
- Review of existing DID management system in ACA-py.
- Identification of suitable plugin architectures.
- **Plugins in ACA-py**
- Plugins are specific pieces of code that are loaded into ACA-py at startup based on the startup configuration
- Capabilities: They can be used to add new routes in existing ACA-py model, change the capabilities of existing routes, create new data models and implement custom protocols that may or may not use aca-py capabilities.
- By using plugins we can create new, seperate endpoints for the existing APIs that uses DID and key capabilities (like credential issuance flow, proof presentation)
- Read more: https://aca-py.org/main/features/PlugIns/
- Simple basic message storage plugin: https://github.com/hyperledger/aries-acapy-plugins/blob/main/basicmessage_storage/basicmessage_storage/v1_0/models.py
**Challenges:**
- When I remove the DID resolver from ACA-py, the agent fails to load as it looks for the DID resolver module while starting up.
- If I remove the DID loading module too, the agent is unable to resolve any DIDs which it tries to resolve internally. The full testing of the agent behaviour is what needs to be done to see which things break.
**Approach:**
- POC requirements:
- Seperate the DID resolve functionality for DID web, key and sov into the plugin and remove them from ACA-py.
- **DID web**
- The resolver for `did:web` lies in the file: `aries_cloudagent/resolver/default/web.py`.
- The file is removed from the location and move into plugin.
- The DID modules are loaded in `aries_cloudagent/resolver/__init__.py`, where line 46-50 is for loading `did:web` resolver. This has been modified so that agent can boot up properly. Instead of loading the internal resolver, ACA-py loads the DID web plugin resolver class.
- **DID sov**
- The resolver for `did:sov` located in the file: `aries_cloudagent/resolver/default/indy.py`.
- Remove the file from the location and move into plugin.
- The DID sov resolver is loaded at `aries_cloudagent/resolver/__init__.py`, line 37-44. This has been modified so that agent can boot up properly. Instead of loading the internal resolver, ACA-py loads the DID sov plugin resolver class.
- **DID Key**
- The resolver for `did:key` is located in `aries_cloudagent/resolver/default/key.py`.
- Removed the file and moved it into plugin.
- Edit the module loading file like previous and add the new plugin there.
- Seperate DID create functionality for `web`, `key`, and `sov` methods.
- The create DID functionality has most of the steps common for any DID method. So we created the plugin such that it adds support for the new DID methods using the same `/wallet/did/create` endpoint.
- The DID methods are defined in `aries_cloudagent/wallet/did_method.py` file. We remove the code sections that initialize the methods `SOV`, `KEY`, and `WEB` from the file and remove them from the `__init__` method of `DIDMethods` class which keeps a track of which DID methods the wallet supports.
- While loading the plugin (at agent startup) we register the DID methods of the respective plugin dynamically.
- Once the DID method gets registered, the agent is able to perform all functions with that DID.
<!-- **Things to note**
When the agent loads, it does not have any DID of it's own and new DIDs registered to the wallet cannot be posted into the ledger as they are not endorser DID. So we need to register a DID into the ledger beforehand so that when we add that DID into wallet it can be made public. -->
**Things to note**
The process of endorsement of transactions using the agent will not be impacted by the external DID plugins.
**Compatibility**
The standalone aca-py and aca-py loaded with the plugin are both remain compatible and all existing APIs continue to work (when the DID modules are loaded) as of version 0.12.1. In case of DID modules missing, the concerned APIs are able to exit gracefully without disrupting the functioning of the agent.
### 3. Optional DID for Out of Band Verifier
#### Objective
Currently, the APIs called by the verifier does not require the verifier's DID, and hence can be used even when the verifier does not possess any DID in it's wallet. Our recommendation is that the verifier should have an option to pass the DID if it chooses to do so. This will help the holder to know the identity of the verifier if it seeks the information. It will also help the holder to confirm the authority of the verifier. The verifier engages with the holder in the following ways:
- OOB proof request
- Connection based proof request
Our recommendation is that in both the above cases, the verifier should have option to pass it's DID.
#### Approach
OOB and connection based proof presentation works fine currently in ACA-py, the functionality we need to add is that the holder is able to check whether any DID of the verifier has been sent with the proof request. If it is sent, the holder should be able to resolve the DID and decide whether to respond or not. This can be done by editing the proof presentation schemas present at `aries_cloudagent/protocols/present_proof/v2_0/messages/pres_request.py` and adding a optional field of `verifier_did` inside it. Note that we also need to check while sending requests whether the provided verifier DID exists in the wallet of the verifier or not.
### 4. ACA-py Bring your own DID
**Objective:**
When we bring an outside DID like `did:web` into ACA-py, the agent creates a new key pair for the wallet and saves it. To use the verification method in the DID document, we then need to update the public key there with the ACA-py verkey. We need to create a plugin for ACA-py that can automate the process of updating the DID, if it is given the access to the DID document server.
**Approach**
- We use a small EC2 instance as a custom DID server and expose endpoints for creating a DID and updating the verification method.
- After we create a DID in the server, when we use the plugin to add the DID into wallet, the plugin calls the ACA-py internal DID register funtions, extracts the verkey, and the calls the API to add the verkey into the DID document.


## Deliverables
- **Documentation:** Detailed reports on findings, approaches, and implementation steps for each task.
- **Prototypes:** Working prototypes demonstrating the implementation of DID:web, plugin-based key management, and anoncreds integration.
- **Final Scope Document:** A comprehensive document combining all findings, approaches, and results.