Repository: sicpa-dlab/peer-did-python (language: python)

Issue:
Release separately or merge changes?
I have another branch of this repo (https://github.com/andrewwhitehead/peer-did-python/tree/upd/pydid) with several changes: 

- Using `pydid` for the DID Document representation
- Adding `@context` entries to resolved DID Documents
- Using the spec-recommended 8-character verification method identifier
- Adding `authentication`, `assertionMethod`, `capabilityInvocation`, and `capabilityDelegation` entries to DID Documents for authentication keys (consistent with did:key)
- Disallowing `=` in peer DIDs (base64url-encoded service should never be padded)

Is there any interest in merging this changes, or should I look at releasing this library separately?

@dbluhm


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 57eb6ba..57dc1aa 100644
--- a/README.md
+++ b/README.md
@@ -19,102 +19,112 @@ See https://github.com/sicpa-dlab/didcomm-demo.
 ## Example
 
 Example code:
-```
-    encryption_keys = [
-        VerificationMaterialAgreement(
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-            value="DmgBSHMqaZiYqwNMEJJuxWzsGGC8jUYADrfSdBrC6L8s",
-        )
-    ]
-    signing_keys = [
-        VerificationMaterialAuthentication(
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-            value="ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7",
-        )
-    ]
-    service = """
-                {
-                    "type": "DIDCommMessaging",
-                    "serviceEndpoint": "https://example.com/endpoint1",
-                    "routingKeys": ["did:example:somemediator#somekey1"],
-                    "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"]
-                }
-              """
-
-    peer_did_algo_0 = create_peer_did_numalgo_0(inception_key=signing_keys[0])
-    peer_did_algo_2 = create_peer_did_numalgo_2(
-        encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-    )
-
-    did_doc_algo_0_json = resolve_peer_did(peer_did=peer_did_algo_0)
-    did_doc_algo_2_json = resolve_peer_did(peer_did=peer_did_algo_2)
 
-    did_doc_algo_0 = DIDDocPeerDID.from_json(did_doc_algo_0_json)
-    did_doc_algo_2 = DIDDocPeerDID.from_json(did_doc_algo_2_json)
+```python
+from peerdid.dids import (
+    create_peer_did_numalgo_0,
+    create_peer_did_numalgo_2,
+    resolve_peer_did,
+)
+from peerdid.keys import Ed25519VerificationKey, X25519KeyAgreementKey
+
+encryption_keys = [
+    X25519KeyAgreementKey.from_base58(
+        "DmgBSHMqaZiYqwNMEJJuxWzsGGC8jUYADrfSdBrC6L8s"
+    )
+]
+signing_keys = [
+    Ed25519VerificationKey.from_base58(
+        "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
+    )
+]
+service = {
+    "type": "DIDCommMessaging",
+    "serviceEndpoint": "https://example.com/endpoint1",
+    "routingKeys": ["did:example:somemediator#somekey1"],
+    "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+}
+
+peer_did_algo_0 = create_peer_did_numalgo_0(inception_key=signing_keys[0])
+peer_did_algo_2 = create_peer_did_numalgo_2(
+    encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
+)
+
+did_doc_algo_0 = resolve_peer_did(peer_did_algo_0)
+did_doc_algo_2 = resolve_peer_did(peer_did_algo_2)
+
+did_doc_algo_0_json = did_doc_algo_0.to_json()
+did_doc_algo_2_json = did_doc_algo_2.to_json()
 ```
 
 Example of DID documents:
 
-    # did_doc_algo_0
-    {
-        "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-        "authentication": [
-          {
-              "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-              "type": "Ed25519VerificationKey2020",
-              "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-              "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-          }
-        ]
-    }
-
-    # did_doc_algo_2
+```jsonc
+// did_doc_algo_0_json
+{
+    "@context": [
+        "https://www.w3.org/ns/did/v1",
+        "https://w3id.org/security/suites/ed25519-2020/v1"
+    ],
+    "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+    "verificationMethod": [
+        {
+            "id": "#6MkqRYqQ",
+            "type": "Ed25519VerificationKey2020",
+            "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+            "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+        }
+    ],
+    "authentication": ["#6MkqRYqQ"],
+    "assertionMethod": ["#6MkqRYqQ"],
+    "capabilityInvocation": ["#6MkqRYqQ"],
+    "capabilityDelegation": ["#6MkqRYqQ"]
+}
+
+// did_doc_algo_2_json
+{
+    "@context": [
+        "https://www.w3.org/ns/did/v1",
+        "https://w3id.org/security/suites/x25519-2020/v1",
+        "https://w3id.org/security/suites/ed25519-2020/v1"
+    ],
+    "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDEiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MSJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfQ",
+    "verificationMethod": [
+        {
+            "id": "#6LSpSrLx",
+            "type": "X25519KeyAgreementKey2020",
+            "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDEiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MSJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfQ",
+            "publicKeyMultibase": "z6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud"
+        },
         {
-           "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-           "authentication": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "type": "Ed25519VerificationKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-               },
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg",
-                   "type": "Ed25519VerificationKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyMultibase": "z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg"
-               }
-           ],
-           "keyAgreement": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-                   "type": "X25519KeyAgreementKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyMultibase": "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
-               }
-           ],
-           "service": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#didcommmessaging-0",
-                   "type": "DIDCommMessaging",
-                   "serviceEndpoint": "https://example.com/endpoint",
-                   "routingKeys": [
-                       "did:example:somemediator#somekey"
-                   ],
-                   "accept": [
-                        "didcomm/v2", "didcomm/aip2;env=rfc587"
-                   ]
-               }
-           ]
-       }
+            "id": "#6MkqRYqQ",
+            "type": "Ed25519VerificationKey2020",
+            "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDEiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MSJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfQ",
+            "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+        }
+    ],
+    "authentication": ["#6MkqRYqQ"],
+    "assertionMethod": ["#6MkqRYqQ"],
+    "keyAgreement": ["#6LSpSrLx"],
+    "capabilityInvocation": ["#6MkqRYqQ"],
+    "capabilityDelegation": ["#6MkqRYqQ"],
+    "service": [
+        {
+            "id": "#didcommmessaging-0",
+            "type": "DIDCommMessaging",
+            "serviceEndpoint": "https://example.com/endpoint1",
+            "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+            "routingKeys": ["did:example:somemediator#somekey1"]
+        }
+    ]
+}
+```
 
 ## Assumptions and limitations
 - Only static layers [1, 2a, 2b](https://identity.foundation/peer-did-method-spec/#layers-of-support) are supported
 - Only `X25519` keys are supported for key agreement
 - Only `Ed25519` keys are supported for authentication
-- Supported verification materials (input and in the resolved DID DOC):
+- Supported verification materials (input and in the resolved DID Document):
   - [Default] 2020 verification materials (`Ed25519VerificationKey2020` and `X25519KeyAgreementKey2020`) with multibase base58 (`publicKeyMultibase`) public key encoding.
   - JWK (`JsonWebKey2020`) using JWK (`publicKeyJwk`) public key encoding 
   - 2018/2019 verification materials (`Ed25519VerificationKey2018` and `X25519KeyAgreementKey2019`) using base58 (`publicKeyBase58`) public key encoding. 
diff --git a/demo/demo.py b/demo/demo.py
index 09b69f8..7aa95d3 100644
--- a/demo/demo.py
+++ b/demo/demo.py
@@ -1,63 +1,47 @@
-from peerdid.did_doc import DIDDocPeerDID
-from peerdid.peer_did import (
+"""Demo application."""
+
+from peerdid.dids import (
     create_peer_did_numalgo_0,
     create_peer_did_numalgo_2,
     resolve_peer_did,
 )
-from peerdid.types import (
-    VerificationMaterialAuthentication,
-    VerificationMaterialAgreement,
-    VerificationMethodTypeAgreement,
-    VerificationMethodTypeAuthentication,
-    VerificationMaterialFormatPeerDID,
-)
+from peerdid.keys import Ed25519VerificationKey, X25519KeyAgreementKey
 
 
 def demo():
+    """Generate peer DIDs using both numalgo methods."""
     encryption_keys = [
-        VerificationMaterialAgreement(
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-            value="DmgBSHMqaZiYqwNMEJJuxWzsGGC8jUYADrfSdBrC6L8s",
+        X25519KeyAgreementKey.from_base58(
+            "DmgBSHMqaZiYqwNMEJJuxWzsGGC8jUYADrfSdBrC6L8s"
         )
     ]
     signing_keys = [
-        VerificationMaterialAuthentication(
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-            value="ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7",
+        Ed25519VerificationKey.from_base58(
+            "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
         )
     ]
-    service = """
-                {
-                    "type": "DIDCommMessaging",
-                    "serviceEndpoint": "https://example.com/endpoint1",
-                    "routingKeys": ["did:example:somemediator#somekey1"],
-                    "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"]
-                }
-            """
+    service = {
+        "type": "DIDCommMessaging",
+        "serviceEndpoint": "https://example.com/endpoint1",
+        "routingKeys": ["did:example:somemediator#somekey1"],
+        "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+    }
 
     peer_did_algo_0 = create_peer_did_numalgo_0(inception_key=signing_keys[0])
     peer_did_algo_2 = create_peer_did_numalgo_2(
         encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
     )
 
-    print("peer_did_algo_0:" + peer_did_algo_0)
+    print("peer_did_algo_0:", peer_did_algo_0)
     print("==================================")
-    print("peer_did_algo_2:" + peer_did_algo_2)
-    print("==================================")
-
-    did_doc_algo_0_json = resolve_peer_did(peer_did=peer_did_algo_0)
-    did_doc_algo_2_json = resolve_peer_did(peer_did=peer_did_algo_2)
-    print("did_doc_algo_0 as JSON:" + did_doc_algo_0_json)
+    print("peer_did_algo_2:", peer_did_algo_2)
     print("==================================")
-    print("did_doc_algo_2 as JSON:" + did_doc_algo_2_json)
 
-    did_doc_algo_0 = DIDDocPeerDID.from_json(did_doc_algo_0_json)
-    did_doc_algo_2 = DIDDocPeerDID.from_json(did_doc_algo_2_json)
-    print("did_doc_algo_0 as object:" + str(did_doc_algo_0.to_dict()))
+    did_doc_algo_0 = resolve_peer_did(peer_did_algo_0)
+    did_doc_algo_2 = resolve_peer_did(peer_did_algo_2)
+    print("did_doc_algo_0 as JSON:", did_doc_algo_0.to_json())
     print("==================================")
-    print("did_doc_algo_2 as object:" + str(did_doc_algo_2.to_dict()))
+    print("did_doc_algo_2 as JSON:", did_doc_algo_2.to_json())
 
 
 if __name__ == "__main__":
diff --git a/peerdid/__init__.py b/peerdid/__init__.py
index 6a9beea..9a0cab6 100644
--- a/peerdid/__init__.py
+++ b/peerdid/__init__.py
@@ -1,1 +1,9 @@
-__version__ = "0.4.0"
+"""Peer DID document generation and resolution."""
+
+from . import core, dids, errors, keys
+
+from pydid import DID, DIDDocument
+
+__version__ = "0.5.0"
+
+__all__ = ["__version__", "core", "errors", "dids", "keys", "DID", "DIDDocument"]
diff --git a/peerdid/core/did_doc_types.py b/peerdid/core/did_doc_types.py
deleted file mode 100644
index df2c6f1..0000000
--- a/peerdid/core/did_doc_types.py
+++ /dev/null
@@ -1,222 +0,0 @@
-from enum import Enum
-from typing import List, Dict, Union, Tuple
-
-from peerdid.core.jwk_okp import get_verification_method_type
-from peerdid.errors import MalformedPeerDIDDocError
-from peerdid.types import (
-    VerificationMethodTypePeerDID,
-    VerificationMethodTypeAuthentication,
-    VerificationMethodTypeAgreement,
-    VerificationMaterialPeerDID,
-    VerificationMaterialFormatPeerDID,
-    VerificationMaterialAuthentication,
-    VerificationMaterialAgreement,
-)
-
-
-class VerificationMethodField(Enum):
-    BASE58 = "publicKeyBase58"
-    MULTIBASE = "publicKeyMultibase"
-    JWK = "publicKeyJwk"
-
-
-SERVICE_ID = "id"
-SERVICE_TYPE = "type"
-SERVICE_ENDPOINT = "serviceEndpoint"
-SERVICE_DIDCOMM_MESSAGING = "DIDCommMessaging"
-SERVICE_ROUTING_KEYS = "routingKeys"
-SERVICE_ACCEPT = "accept"
-
-
-class VerificationMethodPeerDID:
-    def __init__(
-        self, id: str, controller: str, ver_material: VerificationMaterialPeerDID
-    ):
-        self.id = id
-        self.controller = controller
-        self.ver_material = ver_material
-
-    def to_dict(self):
-        return {
-            "id": self.id,
-            "type": self.ver_material.type.value,
-            "controller": self.controller,
-            self.public_key_field.value: self.ver_material.value,
-        }
-
-    @property
-    def public_key_field(self):
-        if self.ver_material.format == VerificationMaterialFormatPeerDID.BASE58:
-            return VerificationMethodField.BASE58
-        elif self.ver_material.format == VerificationMaterialFormatPeerDID.MULTIBASE:
-            return VerificationMethodField.MULTIBASE
-        elif self.ver_material.format == VerificationMaterialFormatPeerDID.JWK:
-            return VerificationMethodField.JWK
-        else:
-            raise ValueError(
-                "Unsupported verification material format "
-                + str(self.ver_material.format)
-            )
-
-    @staticmethod
-    def _get_public_key_format(
-        ver_method_type: VerificationMethodTypePeerDID,
-    ) -> Tuple[VerificationMaterialFormatPeerDID, VerificationMethodField]:
-        if (
-            ver_method_type
-            == VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019
-        ):
-            return (
-                VerificationMaterialFormatPeerDID.BASE58,
-                VerificationMethodField.BASE58,
-            )
-        if (
-            ver_method_type
-            == VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2020
-        ):
-            return (
-                VerificationMaterialFormatPeerDID.MULTIBASE,
-                VerificationMethodField.MULTIBASE,
-            )
-        if ver_method_type == VerificationMethodTypeAgreement.JSON_WEB_KEY_2020:
-            return VerificationMaterialFormatPeerDID.JWK, VerificationMethodField.JWK
-        if (
-            ver_method_type
-            == VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018
-        ):
-            return (
-                VerificationMaterialFormatPeerDID.BASE58,
-                VerificationMethodField.BASE58,
-            )
-        if (
-            ver_method_type
-            == VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020
-        ):
-            return (
-                VerificationMaterialFormatPeerDID.MULTIBASE,
-                VerificationMethodField.MULTIBASE,
-            )
-        if ver_method_type == VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020:
-            return VerificationMaterialFormatPeerDID.JWK, VerificationMethodField.JWK
-        raise ValueError("Unsupported verification method type " + str(ver_method_type))
-
-    @staticmethod
-    def _get_ver_method_type(value: dict) -> VerificationMethodTypePeerDID:
-        ver_method_type_str = value["type"]
-        if (
-            ver_method_type_str
-            == VerificationMethodTypeAgreement.JSON_WEB_KEY_2020.value
-            or ver_method_type_str
-            == VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020.value
-        ):
-            if VerificationMethodField.JWK.value not in value:
-                raise MalformedPeerDIDDocError(
-                    "Invalid verification method: no {} field in {} method type".format(
-                        VerificationMethodField.JWK.value, ver_method_type_str
-                    )
-                )
-            return get_verification_method_type(
-                value[VerificationMethodField.JWK.value]
-            )
-
-        try:
-            return VerificationMethodTypeAgreement(ver_method_type_str)
-        except ValueError:
-            pass
-
-        try:
-            return VerificationMethodTypeAuthentication(ver_method_type_str)
-        except ValueError:
-            pass
-
-        raise MalformedPeerDIDDocError(
-            "Unknown verification method type {}".format(ver_method_type_str)
-        )
-
-    @classmethod
-    def from_dict(cls, value: dict):
-        if "id" not in value:
-            raise MalformedPeerDIDDocError("No 'id' field in method {}".format(value))
-        if "type" not in value:
-            raise MalformedPeerDIDDocError("No 'type' field in method {}".format(value))
-        if "controller" not in value:
-            raise MalformedPeerDIDDocError(
-                "No 'controller' field in method {}".format(value)
-            )
-
-        ver_method_type = cls._get_ver_method_type(value)
-        format, field = cls._get_public_key_format(ver_method_type)
-
-        if field.value not in value:
-            raise MalformedPeerDIDDocError(
-                "No public key field {} in method {}".format(field.value, value)
-            )
-
-        ver_material_cls = (
-            VerificationMaterialAgreement
-            if isinstance(ver_method_type, VerificationMethodTypeAgreement)
-            else VerificationMaterialAuthentication
-        )
-        ver_material = ver_material_cls(
-            value=value[field.value],
-            format=format,
-            type=ver_method_type,
-        )
-
-        return cls(
-            id=value["id"], controller=value["controller"], ver_material=ver_material
-        )
-
-
-class DIDCommServicePeerDID:
-    def __init__(
-        self,
-        id: str,
-        service_endpoint: str,
-        routing_keys: List[str],
-        accept: List[str],
-    ) -> None:
-        self.id = id
-        self.service_endpoint = service_endpoint
-        self.routing_keys = routing_keys
-        self.accept = accept
-
-    def to_dict(self):
-        res = {
-            SERVICE_ID: self.id,
-            SERVICE_TYPE: SERVICE_DIDCOMM_MESSAGING,
-            SERVICE_ENDPOINT: self.service_endpoint,
-            SERVICE_ACCEPT: self.accept,
-        }
-        if self.service_endpoint:
-            res[SERVICE_ENDPOINT] = self.service_endpoint
-        if self.routing_keys:
-            res[SERVICE_ROUTING_KEYS] = self.routing_keys
-        if self.accept:
-            res[SERVICE_ACCEPT] = self.accept
-        return res
-
-    @classmethod
-    def from_dict(cls, value: dict):
-        if not value:
-            return value
-
-        if SERVICE_ID not in value:
-            return value
-
-        if SERVICE_TYPE not in value:
-            return value
-
-        service_type = value[SERVICE_TYPE]
-        if service_type != SERVICE_DIDCOMM_MESSAGING:
-            return value
-
-        return cls(
-            id=value[SERVICE_ID],
-            service_endpoint=value.get(SERVICE_ENDPOINT, ""),
-            routing_keys=value.get(SERVICE_ROUTING_KEYS, []),
-            accept=value.get(SERVICE_ACCEPT, []),
-        )
-
-
-Service = Union[Dict, DIDCommServicePeerDID]
diff --git a/peerdid/core/jwk_okp.py b/peerdid/core/jwk_okp.py
index 89028b7..7cd7dcc 100644
--- a/peerdid/core/jwk_okp.py
+++ b/peerdid/core/jwk_okp.py
@@ -1,28 +1,22 @@
+"""JWK utility methods."""
+
 import json
 
-from peerdid.core.utils import urlsafe_b64encode, urlsafe_b64decode
-from peerdid.errors import MalformedPeerDIDDocError
-from peerdid.types import (
-    VerificationMethodTypePeerDID,
-    VerificationMethodTypeAgreement,
-    VerificationMethodTypeAuthentication,
-    VerificationMaterialPeerDID,
-    VerificationMaterialAuthentication,
-    VerificationMaterialAgreement,
-)
+from typing import Tuple, Union
+
+from .multicodec import Codec
+from .utils import urlsafe_b64encode, urlsafe_b64decode
 
 
-def public_key_to_jwk_dict(
-    public_key: bytes, ver_method_type: VerificationMethodTypePeerDID
-):
+def public_key_to_jwk(public_key: bytes, codec: Codec) -> dict:
     x = urlsafe_b64encode(public_key).decode("utf-8")
 
-    if ver_method_type == VerificationMethodTypeAgreement.JSON_WEB_KEY_2020:
-        crv = "X25519"
-    elif ver_method_type == VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020:
+    if codec == Codec.ED25519:
         crv = "Ed25519"
+    elif codec == Codec.X25519:
+        crv = "X25519"
     else:
-        raise ValueError("Unsupported JWK type: " + ver_method_type.value)
+        raise ValueError("Unsupported JWK codec: {}".format(codec))
 
     return {
         "kty": "OKP",
@@ -31,41 +25,39 @@ def public_key_to_jwk_dict(
     }
 
 
-def jwk_key_to_bytes(ver_material: VerificationMaterialPeerDID) -> bytes:
-    jwk_dict = (
-        json.loads(ver_material.value)
-        if isinstance(ver_material.value, str)
-        else ver_material.value
-    )
-
-    if "crv" not in jwk_dict:
-        raise ValueError("Invalid JWK key - no 'crv' fields: " + ver_material.value)
-    if "x" not in jwk_dict:
-        raise ValueError("Invalid JWK key - no 'x' fields: " + ver_material.value)
-
-    crv = jwk_dict["crv"]
-    if (
-        isinstance(ver_material, VerificationMaterialAuthentication)
-        and crv != "Ed25519"
+def jwk_to_public_key(jwk: Union[str, dict]) -> Tuple[bytes, Codec]:
+    parts = {}
+    try:
+        if isinstance(jwk, str):
+            parts = json.loads(jwk)
+        elif isinstance(jwk, dict):
+            parts = jwk
+    except json.JSONDecodeError:
+        pass
+
+    kty = parts.pop("kty", None)
+    crv = parts.pop("crv", None)
+    x = parts.pop("x", None)
+    if not (
+        kty
+        and isinstance(kty, str)
+        and crv
+        and isinstance(crv, str)
+        and x
+        and isinstance(x, str)
     ):
-        raise TypeError(
-            "Invalid JWK key type - authentication expected: " + ver_material.value
-        )
-    if isinstance(ver_material, VerificationMaterialAgreement) and crv != "X25519":
-        raise TypeError(
-            "Invalid JWK key type - key agreement expected: " + ver_material.value
-        )
+        raise ValueError("Invalid JWK: {}".format(jwk))
 
-    value = jwk_dict["x"]
-    return urlsafe_b64decode(value.encode())
+    try:
+        public_key = urlsafe_b64decode(x)
+    except ValueError as e:
+        raise ValueError("Invalid JWK: {}".format(jwk)) from e
 
+    if crv == "Ed25519":
+        codec = Codec.ED25519
+    elif crv == "X25519":
+        codec = Codec.X25519
+    else:
+        raise ValueError("Unsupported JWK codec: {}".format(crv))
 
-def get_verification_method_type(jwk_dict: dict) -> VerificationMethodTypePeerDID:
-    if "crv" not in jwk_dict:
-        raise MalformedPeerDIDDocError("No 'crv' field in JWK {}".format(jwk_dict))
-    crv = jwk_dict["crv"]
-    return (
-        VerificationMethodTypeAgreement.JSON_WEB_KEY_2020
-        if crv == "X25519"
-        else VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020
-    )
+    return public_key, codec
diff --git a/peerdid/core/multibase.py b/peerdid/core/multibase.py
index 4782f4b..676ecb0 100644
--- a/peerdid/core/multibase.py
+++ b/peerdid/core/multibase.py
@@ -1,26 +1,38 @@
+"""Multibase utility methods."""
+
 from enum import Enum
 from typing import Tuple
 
 import base58
 
 
-class MultibasePrefix(Enum):
+class MultibaseFormat(Enum):
+    """Supported multibase formats."""
+
     BASE58 = "z"
 
 
-def to_base58_multibase(value: bytes) -> str:
-    return MultibasePrefix.BASE58.value + to_base58(value)
+def from_base58(base58encoded: str) -> bytes:
+    """Convert from base58 to bytes."""
+    try:
+        return base58.b58decode(base58encoded)
+    except ValueError:
+        raise ValueError(
+            "Invalid key: Invalid base58 encoding: " + base58encoded
+        ) from None
 
 
 def to_base58(value: bytes) -> str:
+    """Convert a bytes value to base58 encoding."""
     return base58.b58encode(value).decode("utf-8")
 
 
-def from_base58_multibase(multibase: str) -> Tuple[str, bytes]:
+def from_multibase(multibase: str) -> Tuple[str, bytes]:
+    """Convert from multibase to bytes."""
     if not multibase:
         raise ValueError("Invalid key: No transform part in multibase encoding")
     transform = multibase[0]
-    if not transform == MultibasePrefix.BASE58.value:
+    if not transform == MultibaseFormat.BASE58.value:
         raise ValueError(
             "Invalid key: Unsupported transform part of peer_did: " + transform
         )
@@ -29,14 +41,8 @@ def from_base58_multibase(multibase: str) -> Tuple[str, bytes]:
     return encnumbasis, decoded
 
 
-def from_base58(base58encoded: str) -> bytes:
-    if not is_base58(base58encoded):
-        raise ValueError("Invalid key: Invalid base58 encoding: " + base58encoded)
-    decoded = base58.b58decode(base58encoded)
-    return decoded
-
-
-def is_base58(key: str) -> bool:
-    alphabet = set("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
-    invalid_chars = set(key) - alphabet
-    return not invalid_chars
+def to_multibase(value: bytes, format: MultibaseFormat = None) -> str:
+    """Convert to base58-encoded multibase."""
+    if not format or format == MultibaseFormat.BASE58:
+        return MultibaseFormat.BASE58.value + to_base58(value)
+    raise ValueError("Unsupported multibase format")
diff --git a/peerdid/core/multicodec.py b/peerdid/core/multicodec.py
index b466040..3d65b3e 100644
--- a/peerdid/core/multicodec.py
+++ b/peerdid/core/multicodec.py
@@ -1,23 +1,27 @@
+"""Multicodec utility methods."""
+
 from enum import Enum
-from typing import Tuple
+from typing import Tuple, Union
 
 import varint
 
-from peerdid.types import VerificationMethodTypePeerDID, VerificationMethodTypeAgreement
-
 
 class Codec(Enum):
+    """Multicodec supported codecs."""
+
     X25519 = 0xEC
     ED25519 = 0xED
 
+    def encode_multicodec(self, value: bytes) -> bytes:
+        """Encode a value with this codec."""
+        prefix = varint.encode(self.value)
+        return prefix + value
 
-def to_multicodec(value: bytes, key_type: VerificationMethodTypePeerDID) -> bytes:
-    codec = _get_codec(key_type)
-    prefix = varint.encode(codec.value)
-    return b"".join([prefix, value])
 
-
-def from_multicodec(value: bytes) -> Tuple[bytes, Codec]:
+def from_multicodec(value: Union[str, bytes]) -> Tuple[bytes, Codec]:
+    """Decode a multicodec value."""
+    if isinstance(value, str):
+        value = value.encode("utf-8")
     try:
         prefix_int = varint.decode_bytes(value)
     except Exception:
@@ -36,10 +40,3 @@ def from_multicodec(value: bytes) -> Tuple[bytes, Codec]:
 
     prefix = varint.encode(prefix_int)
     return value[len(prefix) :], codec
-
-
-def _get_codec(key_type: VerificationMethodTypePeerDID) -> Codec:
-    if isinstance(key_type, VerificationMethodTypeAgreement):
-        return Codec.X25519
-    else:
-        return Codec.ED25519
diff --git a/peerdid/core/peer_did_helper.py b/peerdid/core/peer_did_helper.py
index fdd495f..2a1c40a 100644
--- a/peerdid/core/peer_did_helper.py
+++ b/peerdid/core/peer_did_helper.py
@@ -1,82 +1,102 @@
+"""Peer DID helper methods."""
+
 import json
-import re
+
 from enum import Enum
-from typing import List, Optional, NamedTuple
-
-from peerdid.core.did_doc_types import (
-    VerificationMethodTypeAgreement,
-    VerificationMethodTypeAuthentication,
-    SERVICE_DIDCOMM_MESSAGING,
-    SERVICE_ENDPOINT,
-    SERVICE_TYPE,
-    SERVICE_ROUTING_KEYS,
-    SERVICE_ACCEPT,
-    SERVICE_ID,
-    VerificationMethodPeerDID,
-)
-from peerdid.core.jwk_okp import jwk_key_to_bytes, public_key_to_jwk_dict
-from peerdid.core.multibase import (
-    from_base58_multibase,
-    from_base58,
-    to_base58_multibase,
-    to_base58,
-)
-from peerdid.core.multicodec import to_multicodec, from_multicodec, Codec
-from peerdid.core.utils import urlsafe_b64encode, urlsafe_b64decode
-from peerdid.core.validation import validate_raw_key_length
-from peerdid.types import (
-    JSON,
-    PEER_DID,
-    VerificationMaterialPeerDID,
-    VerificationMaterialFormatPeerDID,
-    VerificationMaterialAgreement,
-    VerificationMaterialAuthentication,
-)
+from typing import List, Optional, Union
+
+from pydid import Service
+
+from ..core.utils import urlsafe_b64encode, urlsafe_b64decode
+from ..errors import MalformedPeerDIDError
+from ..keys import KeyFormat, BaseKey
+
+SERVICE_ID = "id"
+SERVICE_TYPE = "type"
+SERVICE_ENDPOINT = "serviceEndpoint"
+SERVICE_DIDCOMM_MESSAGING = "DIDCommMessaging"
+SERVICE_ROUTING_KEYS = "routingKeys"
+SERVICE_ACCEPT = "accept"
+
+ServiceJson = Union[str, dict, list]
 
 
 class Numalgo2Prefix(Enum):
+    """Numalgo prefix values."""
+
     AUTHENTICATION = "V"
     KEY_AGREEMENT = "E"
     SERVICE = "S"
 
 
-ServicePrefix = {
-    SERVICE_TYPE: "t",
-    SERVICE_ENDPOINT: "s",
-    SERVICE_DIDCOMM_MESSAGING: "dm",
-    SERVICE_ROUTING_KEYS: "r",
-    SERVICE_ACCEPT: "a",
-}
+class ServicePrefix(Enum):
+    """Service short forms."""
+
+    SERVICE_TYPE = "t"
+    SERVICE_ENDPOINT = "s"
+    SERVICE_DIDCOMM_MESSAGING = "dm"
+    SERVICE_ROUTING_KEYS = "r"
+    SERVICE_ACCEPT = "a"
 
 
-def encode_service(service: JSON) -> str:
+def encode_service(service: ServiceJson) -> str:
     """
-    Generates encoded service according to the second algorithm
-    (https://identity.foundation/peer-did-method-spec/index.html#generation-method)
-    For this type of algorithm did_doc can be obtained from peer_did
-    :param service: JSON string conforming to the DID specification (https://www.w3.org/TR/did-core/#services)
+    Generate encoded service according to the second algorithm.
+
+    Reference: <https://identity.foundation/peer-did-method-spec/index.html#generation-method>
+    For this type of algorithm the DID Document can be obtained from the Peer DID.
+
+    :param service: JSON conforming to the DID specification (https://www.w3.org/TR/did-core/#services)
     :return: encoded service
     """
-    service_to_encode = (
-        re.sub(r"[\n\t\s]*", "", service)
-        .replace(SERVICE_TYPE, ServicePrefix[SERVICE_TYPE])
-        .replace(SERVICE_ENDPOINT, ServicePrefix[SERVICE_ENDPOINT])
-        .replace(SERVICE_DIDCOMM_MESSAGING, ServicePrefix[SERVICE_DIDCOMM_MESSAGING])
-        .replace(SERVICE_ROUTING_KEYS, ServicePrefix[SERVICE_ROUTING_KEYS])
-        .replace(SERVICE_ACCEPT, ServicePrefix[SERVICE_ACCEPT])
-        .encode("utf-8")
-    )
+    if service is None or service == "" or service == []:
+        return ""
+
+    if isinstance(service, str):
+        try:
+            service = json.loads(service)
+        except json.JSONDecodeError:
+            pass
+
+    if isinstance(service, list):
+        service = list(map(_encode_service_entry, service))
+    elif isinstance(service, dict):
+        service = _encode_service_entry(service)
+    else:
+        raise ValueError("Service is not valid JSON")
+
     return (
         "."
         + Numalgo2Prefix.SERVICE.value
-        + urlsafe_b64encode(service_to_encode).decode("utf-8")
+        + urlsafe_b64encode(json.dumps(service, separators=(",", ":"))).decode("utf-8")
     )
 
 
-def decode_service(service: str, peer_did: PEER_DID) -> Optional[List[dict]]:
+def _encode_service_entry(service: dict) -> dict:
+    result = {}
+    for k, v in service.items():
+        if k == SERVICE_TYPE:
+            k = ServicePrefix.SERVICE_TYPE.value
+        elif k == SERVICE_ENDPOINT:
+            k = ServicePrefix.SERVICE_ENDPOINT.value
+        elif k == SERVICE_ROUTING_KEYS:
+            k = ServicePrefix.SERVICE_ROUTING_KEYS.value
+        elif k == SERVICE_ACCEPT:
+            k = ServicePrefix.SERVICE_ACCEPT.value
+
+        if v == SERVICE_DIDCOMM_MESSAGING:
+            v = ServicePrefix.SERVICE_DIDCOMM_MESSAGING.value
+
+        result[k] = v
+    return result
+
+
+def decode_service(service: str) -> Optional[List[Service]]:
     """
-    Decodes service according to Peer DID spec
-    (https://identity.foundation/peer-did-method-spec/index.html#example-2-abnf-for-peer-dids)
+    Decode service according to Peer DID spec.
+
+    Reference: https://identity.foundation/peer-did-method-spec/index.html#example-2-abnf-for-peer-dids
+
     :param service: service to decode
     :param peer_did: peer_did which will be used as an ID
     :raises ValueError: if peer_did parameter is not valid
@@ -84,141 +104,53 @@ def decode_service(service: str, peer_did: PEER_DID) -> Optional[List[dict]]:
     """
     if not service:
         return None
-    decoded_service = urlsafe_b64decode(service.encode())
-    list_of_service_dict = json.loads(decoded_service.decode("utf-8"))
+    try:
+        decoded_service = urlsafe_b64decode(service.encode())
+        list_of_service_dict = json.loads(decoded_service.decode("utf-8"))
+    except (ValueError, json.JSONDecodeError) as e:
+        raise MalformedPeerDIDError("Invalid service") from e
 
     if not isinstance(list_of_service_dict, list):
         list_of_service_dict = [list_of_service_dict]
+    result = []
 
-    for i in range(len(list_of_service_dict)):
-        service = list_of_service_dict[i]
-        if ServicePrefix[SERVICE_TYPE] not in service:
-            raise ValueError("service doesn't contain a type")
-        service_type = service.pop(ServicePrefix[SERVICE_TYPE]).replace(
-            ServicePrefix[SERVICE_DIDCOMM_MESSAGING], SERVICE_DIDCOMM_MESSAGING
+    for i, svc_def in enumerate(list_of_service_dict):
+        if not isinstance(svc_def, dict):
+            raise MalformedPeerDIDError("Service entry is not an object")
+        service_type = svc_def.pop(ServicePrefix.SERVICE_TYPE.value, "").replace(
+            ServicePrefix.SERVICE_DIDCOMM_MESSAGING.value, SERVICE_DIDCOMM_MESSAGING
         )
-        service[SERVICE_ID] = peer_did + "#" + service_type.lower() + "-" + str(i)
-        service[SERVICE_TYPE] = service_type
-        if ServicePrefix[SERVICE_ENDPOINT] in service:
-            service[SERVICE_ENDPOINT] = service.pop(ServicePrefix[SERVICE_ENDPOINT])
-        if ServicePrefix[SERVICE_ROUTING_KEYS] in service:
-            service[SERVICE_ROUTING_KEYS] = service.pop(
-                ServicePrefix[SERVICE_ROUTING_KEYS]
-            )
-        if ServicePrefix[SERVICE_ACCEPT] in service:
-            service[SERVICE_ACCEPT] = service.pop(ServicePrefix[SERVICE_ACCEPT])
-
-    return list_of_service_dict
-
-
-def create_multibase_encnumbasis(key: VerificationMaterialPeerDID) -> str:
-    """
-    Creates multibased encnumbasis according to Peer DID spec
-    (https://identity.foundation/peer-did-method-spec/index.html#method-specific-identifier)
-    :param key: public key
-    :return: transform+encnumbasis
-    """
-    if key.format == VerificationMaterialFormatPeerDID.BASE58:
-        decoded_key = from_base58(key.value)
-    elif key.format == VerificationMaterialFormatPeerDID.MULTIBASE:
-        decoded_key = from_multicodec(from_base58_multibase(key.value)[1])[0]
-    elif key.format == VerificationMaterialFormatPeerDID.JWK:
-        decoded_key = jwk_key_to_bytes(key)
-    else:
-        raise ValueError("Unknown key format " + key.format)
-    validate_raw_key_length(decoded_key)
-    return to_base58_multibase(to_multicodec(decoded_key, key.type))
-
+        if not service_type:
+            raise MalformedPeerDIDError("Service doesn't contain a type")
+        ident = "#" + service_type.lower() + "-" + str(i)
+        endpoint = svc_def.pop(ServicePrefix.SERVICE_ENDPOINT.value, None)
+        extra = {}
+        for k, v in svc_def.items():
+            if k == ServicePrefix.SERVICE_ACCEPT.value:
+                k = SERVICE_ACCEPT
+            elif k == ServicePrefix.SERVICE_ROUTING_KEYS.value:
+                k = SERVICE_ROUTING_KEYS
+            extra[k] = v
+        service = Service.make(
+            id=ident, type=service_type, service_endpoint=endpoint, **extra
+        )
+        result.append(service)
 
-DecodedEncnumbasis = NamedTuple(
-    "DecodedEncnumbasis",
-    [
-        ("encnumbasis", str),
-        ("ver_material", VerificationMaterialPeerDID),
-    ],
-)
+    return result
 
 
-def decode_multibase_encnumbasis(
+def decode_multibase_numbasis(
     multibase: str,
-    ver_material_format: VerificationMaterialFormatPeerDID,
-) -> DecodedEncnumbasis:
-    """
-    Decodes multibased encnumbasis to a verification material for DID DOC
-    :param multibase: transform+encnumbasis to decode
-    :param ver_material_format: the format of public keys in the DID DOC
-    :return: decoded encnumbasis as verification method for DID DOC
+    key_format: KeyFormat,
+) -> BaseKey:
     """
-    encnumbasis, decoded_encnumbasis = from_base58_multibase(multibase)
-    decoded_encnumbasis_without_prefix, codec = from_multicodec(decoded_encnumbasis)
-    validate_raw_key_length(decoded_encnumbasis_without_prefix)
-
-    ver_material_cls = (
-        VerificationMaterialAgreement
-        if codec == Codec.X25519
-        else VerificationMaterialAuthentication
-    )
-    if ver_material_format == VerificationMaterialFormatPeerDID.BASE58:
-        ver_material = ver_material_cls(
-            format=ver_material_format,
-            type=__get_2018_2019_ver_material_type(codec),
-            value=to_base58(decoded_encnumbasis_without_prefix),
-        )
-    elif ver_material_format == VerificationMaterialFormatPeerDID.MULTIBASE:
-        ver_material = ver_material_cls(
-            format=ver_material_format,
-            type=__get_2020_ver_material_type(codec),
-            value=to_base58_multibase(
-                to_multicodec(
-                    decoded_encnumbasis_without_prefix,
-                    __get_2020_ver_material_type(codec),
-                ),
-            ),
-        )
-    elif ver_material_format == VerificationMaterialFormatPeerDID.JWK:
-        ver_material_type = __get_jwk_ver_material_type(codec)
-        ver_material = ver_material_cls(
-            format=ver_material_format,
-            type=ver_material_type,
-            value=public_key_to_jwk_dict(
-                decoded_encnumbasis_without_prefix, ver_material_type
-            ),
-        )
-    else:
-        raise ValueError("Unknown format {}".format(ver_material_format))
+    Decode multibase-encoded numeric basis to a verification method for DID Document.
 
-    return DecodedEncnumbasis(encnumbasis=encnumbasis, ver_material=ver_material)
-
-
-def get_verification_method(
-    did: PEER_DID, decoded_encnumbasis: DecodedEncnumbasis
-) -> VerificationMethodPeerDID:
-    return VerificationMethodPeerDID(
-        id=did + "#" + decoded_encnumbasis.encnumbasis,
-        controller=did,
-        ver_material=decoded_encnumbasis.ver_material,
-    )
-
-
-def __get_2018_2019_ver_material_type(codec: Codec):
-    if codec == Codec.X25519:
-        return VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019
-    elif codec == Codec.ED25519:
-        return VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018
-    raise ValueError("Unknown multicodec {}".format(codec.value))
-
-
-def __get_2020_ver_material_type(codec: Codec):
-    if codec == Codec.X25519:
-        return VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2020
-    elif codec == Codec.ED25519:
-        return VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020
-    raise ValueError("Unknown multicodec {}".format(codec.value))
-
-
-def __get_jwk_ver_material_type(codec: Codec):
-    if codec == Codec.X25519:
-        return VerificationMethodTypeAgreement.JSON_WEB_KEY_2020
-    elif codec == Codec.ED25519:
-        return VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020
-    raise ValueError("Unknown multicodec {}".format(codec.value))
+    :param multibase: multibase-encoded numeric basis to decode
+    :param key_format: the format of public keys in the DID Document
+    :return: decoded numeric basis as verification method for DID Document
+    """
+    try:
+        return BaseKey.from_multibase(multibase, format=key_format)
+    except (ValueError, TypeError) as e:
+        raise MalformedPeerDIDError("Invalid key: {}".format(multibase)) from e
diff --git a/peerdid/core/storage.py b/peerdid/core/storage.py
deleted file mode 100644
index 879eb51..0000000
--- a/peerdid/core/storage.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import os.path
-from abc import ABC, abstractmethod
-from pathlib import Path
-
-
-class Storage(ABC):
-    @abstractmethod
-    def save(self, data: bytes):
-        """
-        Saves data to a storage
-        """
-        pass
-
-    @abstractmethod
-    def load(self) -> bytes:
-        """
-        Loads data from a storage
-        """
-        pass
-
-
-class FileStorage(Storage):
-    DEFAULT_PEERDID_FOLDER_PATH = str(Path.home() / ".peerdids")
-    DEFAULT_PEERDID_FILE_EXTENSION = ".diddoc"
-
-    def __init__(
-        self,
-        peer_did_filename: str,
-        peer_did_storage_folder: str = None,
-        did_doc_file_extension: str = None,
-    ):
-        self.peer_did_storage_folder = (
-            peer_did_storage_folder or self.DEFAULT_PEERDID_FOLDER_PATH
-        )
-        self.peer_did_filename = peer_did_filename
-        self.did_doc_file_extension = (
-            did_doc_file_extension or self.DEFAULT_PEERDID_FILE_EXTENSION
-        )
-
-    def save(self, data: bytes):
-        """
-        Saves data to a storage
-        """
-        file_path = os.path.join(
-            self.peer_did_storage_folder,
-            self.peer_did_filename + self.did_doc_file_extension,
-        )
-        with open(file_path, "bw+") as f:
-            f.write(data)
-
-    def load(self) -> bytes:
-        """
-        Loads data from a storage
-        """
-        file_path = os.path.join(
-            self.peer_did_storage_folder,
-            self.peer_did_filename + self.did_doc_file_extension,
-        )
-        with open(file_path, "rb") as f:
-            data = f.read()
-            return data
diff --git a/peerdid/core/utils.py b/peerdid/core/utils.py
index ae33c20..f25765a 100644
--- a/peerdid/core/utils.py
+++ b/peerdid/core/utils.py
@@ -1,36 +1,36 @@
+"""Utility methods."""
+
 import base64
-import hashlib
+
+from typing import Union
 
 
-def urlsafe_b64encode(s: bytes) -> bytes:
+def urlsafe_b64encode(s: Union[str, bytes]) -> bytes:
     """
-    Base 64 URL safe encoding with no padding.
+    Base64 URL-safe encoding with no padding.
+
     :param s: input str to be encoded
     :return: encoded bytes
     """
+    if isinstance(s, str):
+        s = s.encode("utf-8")
     try:
         return base64.urlsafe_b64encode(s).rstrip(b"=")
     except Exception as e:
         raise ValueError("Can not encode from base64 URL safe: " + str(s)) from e
 
 
-def urlsafe_b64decode(s: bytes) -> bytes:
+def urlsafe_b64decode(s: Union[str, bytes]) -> bytes:
     """
-    Base 64 URL safe decoding with no padding.
+    Base64 URL-safe decoding with no padding.
+
     :param s: input bytes to be decoded
     :return: decoded bytes
     """
+    if isinstance(s, str):
+        s = s.encode("utf-8")
     try:
         s += b"=" * (-len(s) % 4)
         return base64.urlsafe_b64decode(s)
     except Exception as e:
         raise ValueError("Can not decode base64 URL safe: " + str(s)) from e
-
-
-def encode_filename(filename: str) -> str:
-    """
-    Encodes filename to SHA256 string
-    :param filename: name of file
-    :return: encoded filename as SHA256 string
-    """
-    return hashlib.sha256(filename.encode()).hexdigest()
diff --git a/peerdid/core/validation.py b/peerdid/core/validation.py
deleted file mode 100644
index 15f7c4b..0000000
--- a/peerdid/core/validation.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import json
-
-from peerdid.types import (
-    VerificationMaterialAuthentication,
-    VerificationMaterialAgreement,
-)
-
-
-def validate_verification_material_authentication(ver_material):
-    if not isinstance(ver_material, VerificationMaterialAuthentication):
-        raise TypeError(
-            "Invalid verification material type: {} instead of VerificationMaterialAuthentication".format(
-                str(type(ver_material))
-            )
-        )
-
-
-def validate_verification_material_agreement(ver_material):
-    if not isinstance(ver_material, VerificationMaterialAgreement):
-        raise TypeError(
-            "Invalid verification material type: {} instead of VerificationMaterialAgreement".format(
-                str(type(ver_material))
-            )
-        )
-
-
-def validate_service_json(str_to_check: str):
-    """
-    Checks if str is JSON
-    :param str_to_check: string to check
-    :raises ValueError: if str_to_check is not valid JSON
-    """
-    try:
-        if str_to_check is not None:
-            json.loads(str_to_check)
-    except (TypeError, ValueError) as ex:
-        raise ValueError("Service is not a valid JSON") from ex
-
-
-def validate_raw_key_length(key: bytes):
-    # for all supported key types now (ED25519 and X25510) the expected size is 32
-    if len(key) != 32:
-        raise ValueError("Invalid key " + str(key))
diff --git a/peerdid/did_doc.py b/peerdid/did_doc.py
deleted file mode 100644
index c02f5f2..0000000
--- a/peerdid/did_doc.py
+++ /dev/null
@@ -1,82 +0,0 @@
-import json
-from typing import List, Optional
-
-from peerdid.core.did_doc_types import (
-    VerificationMethodPeerDID,
-    Service,
-    DIDCommServicePeerDID,
-)
-from peerdid.errors import MalformedPeerDIDDocError
-from peerdid.types import JSON
-
-
-class DIDDocPeerDID:
-    def __init__(
-        self,
-        did: str,
-        authentication: List[VerificationMethodPeerDID],
-        key_agreement: Optional[List[VerificationMethodPeerDID]] = None,
-        service: Optional[List[Service]] = None,
-    ):
-        self.authentication = authentication
-        self.did = did
-        self.key_agreement = key_agreement
-        self.service = service
-
-    @property
-    def auth_kids(self):
-        return [v.id for v in self.authentication]
-
-    @property
-    def agreement_kids(self):
-        return [v.id for v in self.key_agreement]
-
-    def to_dict(self) -> dict:
-        res = {
-            "id": self.did,
-            "authentication": [a.to_dict() for a in self.authentication],
-        }
-        if self.key_agreement is not None:
-            res["keyAgreement"] = [ka.to_dict() for ka in self.key_agreement]
-        if self.service is not None:
-            res["service"] = self.service
-        return res
-
-    def to_json(self) -> JSON:
-        return json.dumps(self.to_dict(), indent=4)
-
-    @classmethod
-    def from_json(cls, value: JSON):
-        """
-        Creates a new instance of DIDDocPeerDID from the given DID Doc JSON.
-        :param value: DID doc as JSON
-        :raises MalformedPeerDIDDocError: if the JSON can not be converted to a valid DID Doc object
-        :return: a new instance of DIDDocPeerDID
-        """
-        try:
-            did_doc_dict = json.loads(value)
-        except Exception as e:
-            raise MalformedPeerDIDDocError("Invalid JSON") from e
-
-        if "id" not in did_doc_dict:
-            raise MalformedPeerDIDDocError("No 'id' field")
-
-        return cls(
-            did=did_doc_dict["id"],
-            authentication=[
-                VerificationMethodPeerDID.from_dict(v)
-                for v in did_doc_dict.get("authentication", [])
-            ],
-            key_agreement=[
-                VerificationMethodPeerDID.from_dict(v)
-                for v in did_doc_dict.get("keyAgreement", [])
-            ],
-            service=(
-                [
-                    DIDCommServicePeerDID.from_dict(v)
-                    for v in did_doc_dict.get("service")
-                ]
-                if isinstance(did_doc_dict.get("service"), list)
-                else did_doc_dict.get("service")
-            ),
-        )
diff --git a/peerdid/dids.py b/peerdid/dids.py
new file mode 100644
index 0000000..370e679
--- /dev/null
+++ b/peerdid/dids.py
@@ -0,0 +1,191 @@
+"""Peer DID document generation and resolution."""
+
+import re
+
+from typing import Optional, Sequence, Union
+
+from pydid import DID, DIDDocument, DIDDocumentBuilder, DIDUrl, InvalidDIDError
+
+from .core.peer_did_helper import (
+    Numalgo2Prefix,
+    ServiceJson,
+    encode_service,
+    decode_multibase_numbasis,
+    decode_service,
+)
+from .errors import MalformedPeerDIDError
+from .keys import KeyFormat, KeyRelationshipType, BaseKey
+
+PEER_DID_PATTERN = re.compile(
+    r"^did:peer:(([0](z)([1-9a-km-zA-HJ-NP-Z]+))|(2((\.[AEVID](z)([1-9a-km-zA-HJ-NP-Z]+))+"
+    r"(\.(S)[0-9a-zA-Z]*)?)))$"
+)
+
+
+def is_peer_did(peer_did: Union[str, DID]) -> bool:
+    """
+    Check if peer_did parameter matches the Peer DID spec.
+
+    Reference: <https://identity.foundation/peer-did-method-spec/index.html#matching-regex>
+
+    :param peer_did: peer_did to check
+    :return: True if peer_did matches spec, otherwise False
+    """
+    if peer_did is None:
+        return False
+    return bool(PEER_DID_PATTERN.match(peer_did))
+
+
+def create_peer_did_numalgo_0(
+    inception_key: BaseKey,
+) -> str:
+    """
+    Generate a Peer DID according to the zeroth algorithm.
+
+    Reference: <https://identity.foundation/peer-did-method-spec/index.html#generation-method>
+    For this type of algorithm the DID Document is synthesized from the key material.
+
+    :param inception_key: the key that creates the DID and authenticates when exchanging it with the first peer
+    :raises ValueError: the inception key is not a BaseKey supporting authentication
+    :return: generated Peer DID
+    """
+    if KeyRelationshipType.AUTHENTICATION not in inception_key.relationships:
+        raise ValueError(
+            "Authentication not supported for key: {}.".format(inception_key)
+        )
+    return "did:peer:0" + inception_key.to_multibase()
+
+
+def create_peer_did_numalgo_2(
+    encryption_keys: Sequence[BaseKey],
+    signing_keys: Sequence[BaseKey],
+    service: Optional[ServiceJson],
+) -> DID:
+    """
+    Generate a Peer DID according to the second algorithm.
+
+    Reference: <https://identity.foundation/peer-did-method-spec/index.html#generation-method>
+    For this type of algorithm the DID Document is synthesized from the key material.
+
+    :param encryption_keys: list of encryption keys
+    :param signing_keys: list of signing keys
+    :param service: JSON conforming to the DID specification (https://www.w3.org/TR/did-core/#services)
+        or None if there is no services expected for this DID
+    :raises ValueError:
+        1. if at least one of signing keys is not a BaseKey supporting authentication
+        2. if at least one of encryption keys is not a BaseKey supporting key agreement
+        3. if service is not valid JSON
+    :return: generated Peer DID
+    """
+    for k in encryption_keys:
+        if KeyRelationshipType.KEY_AGREEMENT not in k.relationships:
+            raise ValueError("Key agreement not supported for key: {}.".format(k))
+    for k in signing_keys:
+        if KeyRelationshipType.AUTHENTICATION not in k.relationships:
+            raise ValueError("Authentication not supported for key: {}.".format(k))
+
+    enc_sep = "." + Numalgo2Prefix.KEY_AGREEMENT.value
+    auth_sep = "." + Numalgo2Prefix.AUTHENTICATION.value
+    encryption_keys_str = (
+        enc_sep + enc_sep.join(key.to_multibase() for key in encryption_keys)
+        if encryption_keys
+        else ""
+    )
+    auth_keys_str = (
+        auth_sep + auth_sep.join(key.to_multibase() for key in signing_keys)
+        if signing_keys
+        else ""
+    )
+    service_str = encode_service(service)
+
+    peer_did = DID("did:peer:2" + encryption_keys_str + auth_keys_str + service_str)
+    return peer_did
+
+
+def resolve_peer_did(
+    peer_did: Union[str, DID],
+    format: KeyFormat = KeyFormat.MULTIBASE,
+) -> DIDDocument:
+    """
+    Resolve a DID Document from a Peer DID.
+
+    :param peer_did: Peer DID to resolve
+    :param format: the format of public keys in the DID Document. Default format is multibase.
+    :raises MalformedPeerDIDError: if peer_did parameter does not match Peer DID spec
+    :return: resolved DID Document as a JSON string
+    """
+    if not is_peer_did(peer_did):
+        raise MalformedPeerDIDError("Does not match peer DID regexp")
+    if peer_did[9] == "0":
+        did_doc = _build_did_doc_numalgo_0(peer_did, format)
+    else:
+        did_doc = _build_did_doc_numalgo_2(peer_did, format)
+    return did_doc
+
+
+def _did_document_builder(peer_did: Union[str, DID]) -> DIDDocumentBuilder:
+    try:
+        return DIDDocumentBuilder(
+            peer_did, context=DIDDocumentBuilder.DEFAULT_CONTEXT.copy()
+        )
+    except InvalidDIDError as e:
+        raise MalformedPeerDIDError("Invalid peer DID") from e
+
+
+def _add_key_to_document(builder: DIDDocumentBuilder, key: BaseKey):
+    ver_method_result = key.verification_method(builder.id)
+    builder.verification_method.methods.append(ver_method_result.method)
+    ver_ident = DIDUrl.parse(ver_method_result.method.id)
+    if ver_method_result.context and ver_method_result.context not in builder.context:
+        builder.context.append(ver_method_result.context)
+    for rel in key.relationships:
+        if rel == KeyRelationshipType.AUTHENTICATION:
+            builder.authentication.reference(ver_ident)
+            builder.assertion_method.reference(ver_ident)
+            builder.capability_delegation.reference(ver_ident)
+            builder.capability_invocation.reference(ver_ident)
+        elif rel == KeyRelationshipType.KEY_AGREEMENT:
+            builder.key_agreement.reference(ver_ident)
+
+
+def _build_did_doc_numalgo_0(
+    peer_did: Union[str, DID], format: KeyFormat
+) -> DIDDocument:
+    decoded_key = decode_multibase_numbasis(peer_did[10:], format)
+    builder = _did_document_builder(peer_did)
+    _add_key_to_document(builder, decoded_key)
+    return builder.build()
+
+
+def _build_did_doc_numalgo_2(
+    peer_did: Union[str, DID], format: KeyFormat
+) -> DIDDocument:
+    keys = peer_did[11:]
+    keys = keys.split(".")
+    builder = _did_document_builder(peer_did)
+
+    for key in keys:
+        if not key:
+            raise MalformedPeerDIDError("Blank key entry")
+        prefix = key[0]
+        if prefix == Numalgo2Prefix.SERVICE.value:
+            for svc in decode_service(key[1:]):
+                builder.service.services.append(svc)
+        elif prefix == Numalgo2Prefix.AUTHENTICATION.value:
+            decoded_key = decode_multibase_numbasis(key[1:], format)
+            if KeyRelationshipType.AUTHENTICATION not in decoded_key.relationships:
+                raise MalformedPeerDIDError(
+                    "Authentication not supported for key: {}.".format(key)
+                )
+            _add_key_to_document(builder, decoded_key)
+        elif prefix == Numalgo2Prefix.KEY_AGREEMENT.value:
+            decoded_key = decode_multibase_numbasis(key[1:], format)
+            if KeyRelationshipType.KEY_AGREEMENT not in decoded_key.relationships:
+                raise MalformedPeerDIDError(
+                    "Key agreement not supported for key: {}.".format(key)
+                )
+            _add_key_to_document(builder, decoded_key)
+        else:
+            raise MalformedPeerDIDError("Unknown prefix: {}.".format(prefix))
+
+    return builder.build()
diff --git a/peerdid/errors.py b/peerdid/errors.py
index 5b45d6b..dac6a0d 100644
--- a/peerdid/errors.py
+++ b/peerdid/errors.py
@@ -1,12 +1,13 @@
+"""Error classes."""
+
+
 class PeerDIDError(Exception):
-    pass
+    """Base class for Peer DID exceptions."""
 
 
 class MalformedPeerDIDError(PeerDIDError):
-    def __init__(self, msg: str) -> None:
-        super().__init__("Invalid peer DID provided. {}.".format(msg))
-
+    """An invalid peer DID was provided."""
 
-class MalformedPeerDIDDocError(PeerDIDError, ValueError):
     def __init__(self, msg: str) -> None:
-        super().__init__("Invalid peer DID Doc. {}.".format(msg))
+        """Initializer."""
+        super().__init__("Invalid peer DID provided. {}.".format(msg))
diff --git a/peerdid/keys.py b/peerdid/keys.py
new file mode 100644
index 0000000..c0d158f
--- /dev/null
+++ b/peerdid/keys.py
@@ -0,0 +1,254 @@
+"""Peer DID key handling."""
+
+from abc import ABC, abstractmethod
+from enum import Enum
+from typing import List, Optional, NamedTuple, Type, Union
+from uuid import uuid4
+
+from pydid import DID, DIDUrl, VerificationMethod
+from pydid.verification_method import (
+    Ed25519VerificationKey2018,
+    Ed25519VerificationKey2020,
+    JsonWebKey2020,
+    X25519KeyAgreementKey2019,
+    X25519KeyAgreementKey2020,
+)
+
+from .core.jwk_okp import jwk_to_public_key, public_key_to_jwk
+from .core.multibase import (
+    MultibaseFormat,
+    from_base58,
+    from_multibase,
+    to_base58,
+    to_multibase,
+)
+from .core.multicodec import Codec, from_multicodec
+
+ED25519_KEY_LENGTH = 32
+ED25519_2020_CONTEXT = "https://w3id.org/security/suites/ed25519-2020/v1"
+X25519_KEY_LENGTH = 32
+X25519_2020_CONTEXT = "https://w3id.org/security/suites/x25519-2020/v1"
+JWS_2020_CONTEXT = "https://w3id.org/security/suites/jws-2020/v1"
+
+
+class KeyFormat(Enum):
+    """Supported key output formats."""
+
+    JWK = 1
+    BASE58 = 2
+    MULTIBASE = 3
+
+
+class KeyRelationshipType(Enum):
+    """Supported key relationship types."""
+
+    AUTHENTICATION = 1
+    KEY_AGREEMENT = 2
+
+
+VerificationMethodResult = NamedTuple(
+    "VerificationMethodResult",
+    [
+        ("context", Optional[str]),
+        ("method", VerificationMethod),
+    ],
+)
+
+
+class BaseKey(ABC):
+    """Base class for key types."""
+
+    codec: Codec
+    format: KeyFormat
+    ident: Optional[Union[str, DIDUrl]] = None
+    key_length: Optional[int] = None
+    public_key: bytes
+    relationships: List[KeyRelationshipType]
+
+    @classmethod
+    def for_codec(cls, codec: Codec) -> Type["BaseKey"]:
+        """Get the BaseKey subclass for a specific codec and key format."""
+        cls_codec = getattr(cls, "codec", None)
+        if cls_codec:
+            if cls_codec != codec:
+                raise ValueError(
+                    "Codec mismatch: expected {}, found {}".format(cls_codec, codec)
+                )
+            return cls
+
+        if codec == Codec.ED25519:
+            return Ed25519VerificationKey
+        elif codec == Codec.X25519:
+            return X25519KeyAgreementKey
+        raise ValueError("Unsupported codec")
+
+    @classmethod
+    def from_base58(
+        cls,
+        enc_key: str,
+        codec: Codec = None,
+        ident: Union[str, DIDUrl] = None,
+        format: KeyFormat = None,
+    ) -> "BaseKey":
+        """Load a base58-encoded key."""
+        codec = codec or getattr(cls, "codec", None)
+        if not codec:
+            raise ValueError("Unspecified codec")
+        public_key = from_base58(enc_key)
+        key_type_cls = cls.for_codec(codec)
+        return key_type_cls(public_key, ident=ident, format=format or KeyFormat.BASE58)
+
+    @classmethod
+    def from_multibase(
+        cls, multibase: str, ident: Union[str, DIDUrl] = None, format: KeyFormat = None
+    ) -> "BaseKey":
+        """Load a multibase, multicodec-encoded key."""
+        encnumbasis, multicodec = from_multibase(multibase)
+        ident = ident or "#" + encnumbasis[:8]
+        public_key, codec = from_multicodec(multicodec)
+        key_type_cls = cls.for_codec(codec)
+        return key_type_cls(
+            public_key, ident=ident, format=format or KeyFormat.MULTIBASE
+        )
+
+    @classmethod
+    def from_jwk(
+        cls,
+        jwk: Union[str, dict],
+        ident: Union[str, DIDUrl] = None,
+        format: KeyFormat = None,
+    ) -> "BaseKey":
+        """Load a JWK key."""
+        public_key, codec = jwk_to_public_key(jwk)
+        key_type_cls = cls.for_codec(codec)
+        return key_type_cls(public_key, ident=ident, format=format or KeyFormat.JWK)
+
+    def __init__(
+        self,
+        public_key: bytes,
+        ident: Union[str, DIDUrl] = None,
+        format: KeyFormat = None,
+    ):
+        """Initializer."""
+        self.public_key = public_key
+        self.ident = ident or "#" + str(uuid4)
+        self.format = format or KeyFormat.MULTIBASE
+        self.validate()
+
+    def validate(self):
+        """Validate the key.
+
+        :raises ValueError: if the public key is invalid
+        """
+        if self.key_length and len(self.public_key) != self.key_length:
+            raise ValueError(
+                "Invalid public key, expected {} bytes".format(self.key_length)
+            )
+
+    @abstractmethod
+    def verification_method(
+        self, controller: Union[str, DID], format: KeyFormat = None, **extra
+    ) -> VerificationMethodResult:
+        """Generate a VerificationMethod entry for this key."""
+
+    def to_multibase(self, format: MultibaseFormat = None) -> str:
+        """Encode this key in multibase format."""
+        return to_multibase(self.codec.encode_multicodec(self.public_key), format)
+
+    def __eq__(self, other: object) -> bool:
+        """Compare to another key for equality."""
+        if self.__class__ is not other.__class__:
+            return False
+        return self.public_key == other.public_key
+
+    def __repr__(self) -> str:
+        """Key representation."""
+        return "<{} {}>".format(self.__class__.__name__, self.to_multibase())
+
+
+class Ed25519VerificationKey(BaseKey):
+    """Ed25519 verification key."""
+
+    codec = Codec.ED25519
+    key_length = ED25519_KEY_LENGTH
+    relationships = [KeyRelationshipType.AUTHENTICATION]
+
+    def verification_method(
+        self, controller: Union[str, DID], format: KeyFormat = None, **extra
+    ) -> VerificationMethodResult:
+        """Generate a VerificationMethod entry for this key."""
+        method = None
+        context = None
+
+        format = format or self.format
+        if format == KeyFormat.BASE58:
+            method = Ed25519VerificationKey2018.make(
+                id=self.ident,
+                controller=controller,
+                public_key_base58=to_base58(self.public_key),
+                **extra
+            )
+        elif format == KeyFormat.MULTIBASE:
+            context = ED25519_2020_CONTEXT
+            method = Ed25519VerificationKey2020.make(
+                id=self.ident,
+                controller=controller,
+                public_key_multibase=to_multibase(
+                    self.codec.encode_multicodec(self.public_key)
+                ),
+                **extra
+            )
+        elif format == KeyFormat.JWK:
+            context = JWS_2020_CONTEXT
+            jwk = public_key_to_jwk(self.public_key, self.codec)
+            method = JsonWebKey2020.make(
+                id=self.ident, controller=controller, public_key_jwk=jwk, **extra
+            )
+
+        if not method:
+            raise ValueError("Unsupported key format for export")
+        return VerificationMethodResult(context, method)
+
+
+class X25519KeyAgreementKey(BaseKey):
+    """X25519 public encryption key."""
+
+    codec = Codec.X25519
+    key_length = X25519_KEY_LENGTH
+    relationships = [KeyRelationshipType.KEY_AGREEMENT]
+
+    def verification_method(
+        self, controller: Union[str, DID], format: KeyFormat = None, **extra
+    ) -> VerificationMethodResult:
+        """Generate a VerificationMethod entry for this key."""
+        method = None
+        context = None
+
+        format = format or self.format
+        if format == KeyFormat.BASE58:
+            method = X25519KeyAgreementKey2019.make(
+                id=self.ident,
+                controller=controller,
+                public_key_base58=to_base58(self.public_key),
+                **extra
+            )
+        elif format == KeyFormat.MULTIBASE:
+            context = X25519_2020_CONTEXT
+            method = X25519KeyAgreementKey2020.make(
+                id=self.ident,
+                controller=controller,
+                public_key_multibase=to_multibase(
+                    self.codec.encode_multicodec(self.public_key)
+                ),
+                **extra
+            )
+        elif format == KeyFormat.JWK:
+            context = JWS_2020_CONTEXT
+            jwk = public_key_to_jwk(self.public_key, self.codec)
+            method = JsonWebKey2020.make(
+                id=self.ident, controller=controller, public_key_jwk=jwk, **extra
+            )
+
+        if not method:
+            raise ValueError("Unsupported key format for export")
+        return VerificationMethodResult(context, method)
diff --git a/peerdid/peer_did.py b/peerdid/peer_did.py
deleted file mode 100644
index 39fc2ae..0000000
--- a/peerdid/peer_did.py
+++ /dev/null
@@ -1,219 +0,0 @@
-import re
-from typing import List, Optional
-
-from peerdid.core.peer_did_helper import (
-    create_multibase_encnumbasis,
-    Numalgo2Prefix,
-    encode_service,
-    decode_multibase_encnumbasis,
-    decode_service,
-    get_verification_method,
-)
-from peerdid.core.validation import (
-    validate_verification_material_authentication,
-    validate_verification_material_agreement,
-    validate_service_json,
-)
-from peerdid.did_doc import DIDDocPeerDID
-from peerdid.errors import MalformedPeerDIDError
-from peerdid.types import (
-    PEER_DID,
-    JSON,
-    VerificationMaterialAuthentication,
-    VerificationMaterialAgreement,
-    VerificationMaterialFormatPeerDID,
-)
-
-
-def is_peer_did(peer_did: PEER_DID) -> bool:
-    """
-    Checks if peer_did parameter matches Peer DID spec
-    (https://identity.foundation/peer-did-method-spec/index.html#matching-regex)
-    :param peer_did: peer_did to check
-    :return: True if peer_did matches spec, otherwise False
-    """
-    if peer_did is None:
-        return False
-    peer_did_pattern = re.compile(
-        r"^did:peer:(([0](z)([1-9a-km-zA-HJ-NP-Z]{46,47}))|(2((\.[AEVID](z)([1-9a-km-zA-HJ-NP-Z]{46,47}))+"
-        r"(\.(S)[0-9a-zA-Z=]*)?)))$"
-    )
-    return bool(re.match(peer_did_pattern, peer_did))
-
-
-def create_peer_did_numalgo_0(
-    inception_key: VerificationMaterialAuthentication,
-) -> PEER_DID:
-    """
-    Generates peer_did according to the zero algorithm
-    (https://identity.foundation/peer-did-method-spec/index.html#generation-method).
-    For this type of algorithm did_doc can be obtained from peer_did.
-
-    :param inception_key: the key that creates the DID and authenticates when exchanging it with the first peer
-    :raises TypeError: if the inception_key is not instance of VerificationMaterialAuthentication
-    :raises ValueError: if the inception_key is not correctly encoded
-    :return: generated peer_did
-    """
-    validate_verification_material_authentication(inception_key)
-    return "did:peer:0" + create_multibase_encnumbasis(inception_key)
-
-
-def create_peer_did_numalgo_2(
-    encryption_keys: List[VerificationMaterialAgreement],
-    signing_keys: List[VerificationMaterialAuthentication],
-    service: Optional[JSON],
-) -> PEER_DID:
-    """
-    Generates peer_did according to the second algorithm
-    (https://identity.foundation/peer-did-method-spec/index.html#generation-method).
-    For this type of algorithm did_doc can be obtained from peer_did.
-
-    :param encryption_keys: list of encryption keys
-    :param signing_keys: list of signing keys
-    :param service: JSON string conforming to the DID specification (https://www.w3.org/TR/did-core/#services)
-        or None if there is no services expected for this DID
-    :raises TypeError:
-        1. if at least one of encryption keys is not instance of VerificationMaterialAgreement or
-            at least one of signing keys is not instance of VerificationMaterialAuthentication
-        2. if service is not JSON type
-    :raises ValueError:
-        1. if at least one of keys is not properly encoded
-        2. if service is not valid JSON
-    :return: generated peer_did
-    """
-    for k in encryption_keys:
-        validate_verification_material_agreement(k)
-    for k in signing_keys:
-        validate_verification_material_authentication(k)
-    validate_service_json(service)
-
-    enc_sep = "." + Numalgo2Prefix.KEY_AGREEMENT.value
-    auth_sep = "." + Numalgo2Prefix.AUTHENTICATION.value
-    encryption_keys_str = (
-        enc_sep
-        + enc_sep.join(create_multibase_encnumbasis(key) for key in encryption_keys)
-        if encryption_keys
-        else ""
-    )
-    auth_keys_str = (
-        auth_sep
-        + auth_sep.join(create_multibase_encnumbasis(key) for key in signing_keys)
-        if signing_keys
-        else ""
-    )
-    service_str = encode_service(service) if service else ""
-
-    peer_did = "did:peer:2" + encryption_keys_str + auth_keys_str + service_str
-    return peer_did
-
-
-def resolve_peer_did(
-    peer_did: PEER_DID,
-    format: VerificationMaterialFormatPeerDID = VerificationMaterialFormatPeerDID.MULTIBASE,
-) -> JSON:
-    """
-    Resolves did_doc from peer_did.
-
-    :param peer_did: peer_did to resolve
-    :param format: the format of public keys in the DID DOC. Default format is multibase.
-    :raises MalformedPeerDIDError: if peer_did parameter does not match peer_did spec
-    :return: resolved did_doc as a JSON string
-    """
-    if not is_peer_did(peer_did):
-        raise MalformedPeerDIDError("Does not match peer DID regexp")
-    if peer_did[9] == "0":
-        did_doc = _build_did_doc_numalgo_0(peer_did=peer_did, format=format)
-    else:
-        did_doc = _build_did_doc_numalgo_2(peer_did=peer_did, format=format)
-    return did_doc.to_json()
-
-
-def _build_did_doc_numalgo_0(
-    peer_did: PEER_DID, format: VerificationMaterialFormatPeerDID
-) -> DIDDocPeerDID:
-    decoded_encnumbasis = __do_decode_multibase_encnumbasis_auth(peer_did[10:], format)
-    return DIDDocPeerDID(
-        did=peer_did,
-        authentication=[get_verification_method(peer_did, decoded_encnumbasis)],
-    )
-
-
-def _build_did_doc_numalgo_2(
-    peer_did: PEER_DID, format: VerificationMaterialFormatPeerDID
-) -> DIDDocPeerDID:
-    keys = peer_did[11:]
-    keys = keys.split(".")
-    service = ""
-    authentication = []
-    key_agreement = []
-
-    for key in keys:
-        prefix = key[0]
-        if prefix == Numalgo2Prefix.SERVICE.value:
-            service = key[1:]
-        elif prefix == Numalgo2Prefix.AUTHENTICATION.value:
-            decoded_encnumbasis = __do_decode_multibase_encnumbasis_auth(
-                key[1:], format
-            )
-            authentication.append(
-                get_verification_method(peer_did, decoded_encnumbasis)
-            )
-        elif prefix == Numalgo2Prefix.KEY_AGREEMENT.value:
-            decoded_encnumbasis = __do_decode_multibase_encnumbasis_agreement(
-                key[1:], format
-            )
-            key_agreement.append(get_verification_method(peer_did, decoded_encnumbasis))
-        else:
-            raise MalformedPeerDIDError("Unknown prefix: {}.".format(prefix))
-    decoded_service = __do_decode_service(service, peer_did)
-
-    return DIDDocPeerDID(
-        did=peer_did,
-        authentication=authentication,
-        key_agreement=key_agreement,
-        service=decoded_service,
-    )
-
-
-def __do_decode_multibase_encnumbasis_auth(
-    multibase: str, ver_material_format: VerificationMaterialFormatPeerDID
-):
-    try:
-        decoded_encnumbasis = decode_multibase_encnumbasis(
-            multibase, ver_material_format
-        )
-        validate_verification_material_authentication(decoded_encnumbasis.ver_material)
-        return decoded_encnumbasis
-    except (ValueError, TypeError) as e:
-        raise MalformedPeerDIDError("Invalid key {}".format(multibase)) from e
-
-
-def __do_decode_multibase_encnumbasis_agreement(
-    multibase: str, ver_material_format: VerificationMaterialFormatPeerDID
-):
-    try:
-        decoded_encnumbasis = decode_multibase_encnumbasis(
-            multibase, ver_material_format
-        )
-        validate_verification_material_agreement(decoded_encnumbasis.ver_material)
-        return decoded_encnumbasis
-    except (ValueError, TypeError) as e:
-        raise MalformedPeerDIDError("Invalid key {}".format(multibase)) from e
-
-
-def __do_decode_service(service: str, peer_did: PEER_DID):
-    try:
-        return decode_service(service, peer_did)
-    except (ValueError, TypeError) as e:
-        raise MalformedPeerDIDError("Invalid service") from e
-
-
-# the method is not needed for the static layer, because did_doc can be obtained from peer_did and vice versa.
-# But the method will be needed for dynamic layer support
-# def save_did_doc(did_doc: JSON, storage: Optional[Storage]):
-#     """
-#     Saves did_doc to a storage
-#     :param did_doc: did_doc to save
-#     :param storage: repository responsible for did_doc saving
-#     """
-#     pass
diff --git a/peerdid/types.py b/peerdid/types.py
deleted file mode 100644
index 0e0b377..0000000
--- a/peerdid/types.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from enum import Enum
-from typing import NamedTuple, Union
-
-
-class VerificationMaterialFormatPeerDID(Enum):
-    JWK = 1
-    BASE58 = 2
-    MULTIBASE = 3
-
-
-class VerificationMethodTypeAgreement(Enum):
-    JSON_WEB_KEY_2020 = "JsonWebKey2020"
-    X25519_KEY_AGREEMENT_KEY_2019 = "X25519KeyAgreementKey2019"
-    X25519_KEY_AGREEMENT_KEY_2020 = "X25519KeyAgreementKey2020"
-
-    @classmethod
-    def values(cls):
-        return [e.value for e in cls]
-
-
-class VerificationMethodTypeAuthentication(Enum):
-    JSON_WEB_KEY_2020 = "JsonWebKey2020"
-    ED25519_VERIFICATION_KEY_2018 = "Ed25519VerificationKey2018"
-    ED25519_VERIFICATION_KEY_2020 = "Ed25519VerificationKey2020"
-
-    @classmethod
-    def values(cls):
-        return [e.value for e in cls]
-
-
-VerificationMethodTypePeerDID = Union[
-    VerificationMethodTypeAgreement, VerificationMethodTypeAuthentication
-]
-
-VerificationMaterialAuthentication = NamedTuple(
-    "VerificationMaterialAuthentication",
-    [
-        ("format", VerificationMaterialFormatPeerDID),
-        ("type", VerificationMethodTypeAuthentication),
-        ("value", Union[str, dict]),
-    ],
-)
-
-VerificationMaterialAgreement = NamedTuple(
-    "VerificationMaterialAgreement",
-    [
-        ("format", VerificationMaterialFormatPeerDID),
-        ("type", VerificationMethodTypeAgreement),
-        ("value", Union[str, dict]),
-    ],
-)
-
-
-VerificationMaterialPeerDID = Union[
-    VerificationMaterialAuthentication, VerificationMaterialAgreement
-]
-
-JSON = str
-PEER_DID = str


Test patch:
diff --git a/tests/test_create_peer_did_numalgo_0.py b/tests/test_create_peer_did_numalgo_0.py
index 5a7773c..32aba3b 100644
--- a/tests/test_create_peer_did_numalgo_0.py
+++ b/tests/test_create_peer_did_numalgo_0.py
@@ -2,58 +2,44 @@
 
 import pytest
 
-from peerdid.peer_did import create_peer_did_numalgo_0, is_peer_did
-from peerdid.types import (
-    VerificationMaterialAuthentication,
-    VerificationMethodTypeAuthentication,
-    VerificationMaterialFormatPeerDID,
-    VerificationMaterialAgreement,
-    VerificationMethodTypeAgreement,
-)
+from peerdid.dids import create_peer_did_numalgo_0, is_peer_did
+from peerdid.keys import Ed25519VerificationKey, X25519KeyAgreementKey
 
 
 @pytest.mark.parametrize(
     "ver_material",
     [
         pytest.param(
-            VerificationMaterialAuthentication(
-                value="ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-                format=VerificationMaterialFormatPeerDID.BASE58,
+            Ed25519VerificationKey.from_base58(
+                "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
             ),
             id="ED25519_VERIFICATION_KEY_2018_BASE58",
         ),
         pytest.param(
-            VerificationMaterialAuthentication(
-                value="z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.MULTIBASE,
+            Ed25519VerificationKey.from_multibase(
+                "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
             ),
             id="ED25519_VERIFICATION_KEY_2020_MULTIBASE",
         ),
         pytest.param(
-            VerificationMaterialAuthentication(
-                value={
+            Ed25519VerificationKey.from_jwk(
+                {
                     "kty": "OKP",
                     "crv": "Ed25519",
                     "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA",
                 },
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
             ),
             id="JSON_WEB_KEY_2020_JWK_DICT",
         ),
         pytest.param(
-            VerificationMaterialAuthentication(
-                value=json.dumps(
+            Ed25519VerificationKey.from_jwk(
+                json.dumps(
                     {
                         "kty": "OKP",
                         "crv": "Ed25519",
                         "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA",
                     }
-                ),
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
+                )
             ),
             id="JSON_WEB_KEY_2020_JWK_JSON",
         ),
@@ -71,193 +57,29 @@ def test_create_numalgo_0_positive(ver_material):
     "ver_material",
     [
         pytest.param(
-            VerificationMaterialAuthentication(
-                value="x8xB2pv7cw8q1Pd0DacS",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-                format=VerificationMaterialFormatPeerDID.BASE58,
-            ),
-            id="ED25519_VERIFICATION_KEY_2018_BASE58",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value="zx8xB2pv7cw8q1Pd0DacS",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.MULTIBASE,
-            ),
-            id="ED25519_VERIFICATION_KEY_2020_MULTIBASE",
-        ),
-    ],
-)
-def test_create_numalgo_0_malformed_inception_key_not_base58_encoded(ver_material):
-    with pytest.raises(ValueError, match=r"Invalid key: Invalid base58 encoding"):
-        create_peer_did_numalgo_0(inception_key=ver_material)
-
-
-@pytest.mark.parametrize(
-    "ver_material",
-    [
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value="ByHnp",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-                format=VerificationMaterialFormatPeerDID.BASE58,
-            ),
-            id="ED25519_VERIFICATION_KEY_2018_BASE58",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value="zByHnp",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.MULTIBASE,
-            ),
-            id="ED25519_VERIFICATION_KEY_2020_MULTIBASE",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value={"kty": "OKP", "crv": "Ed25519", "x": "owBhCbktDjkfS6"},
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
-            ),
-            id="JSON_WEB_KEY_2020_JWK_DICT",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value=json.dumps({"kty": "OKP", "crv": "Ed25519", "x": "owBhCbktDjkf"}),
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
-            ),
-            id="JSON_WEB_KEY_2020_JWK_JSON",
-        ),
-    ],
-)
-def test_create_numalgo_0_malformed_short_inception_key(ver_material):
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_0(inception_key=ver_material)
-
-
-@pytest.mark.parametrize(
-    "ver_material",
-    [
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value="ByHnpUCFb1vAfh9CFZ8ByHnpUCFbZkmUZguURW8HnpUCFbZkmUnByHnpUCFbSHnpUCFbZkmUw889hByHnpUCFby6rD8L7",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-                format=VerificationMaterialFormatPeerDID.BASE58,
-            ),
-            id="ED25519_VERIFICATION_KEY_2018_BASE58",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value="zByHnpUCFb1vAfh9CFZ8ByHnpUCFbZkmUZguURW8HnpUCFbZkmUnByHnpUCFbSHnpUCFbZkmUw889hByHnpUCFby6rD8L7",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.MULTIBASE,
-            ),
-            id="ED25519_VERIFICATION_KEY_2020_MULTIBASE",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value={
-                    "kty": "OKP",
-                    "crv": "Ed25519",
-                    "x": "owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6",
-                },
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
-            ),
-            id="JSON_WEB_KEY_2020_JWK_DICT",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value=json.dumps(
-                    {
-                        "kty": "OKP",
-                        "crv": "Ed25519",
-                        "x": "owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6owBhCbktDjkfS6",
-                    }
-                ),
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
-            ),
-            id="JSON_WEB_KEY_2020_JWK_JSON",
-        ),
-    ],
-)
-def test_create_numalgo_0_malformed_long_inception_key(ver_material):
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_0(inception_key=ver_material)
-
-
-@pytest.mark.parametrize(
-    "ver_material",
-    [
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value="",
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-                format=VerificationMaterialFormatPeerDID.BASE58,
-            ),
-            id="ED25519_VERIFICATION_KEY_2018_BASE58",
-        ),
-        pytest.param(
-            VerificationMaterialAuthentication(
-                value={"kty": "OKP", "crv": "Ed25519", "x": ""},
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
-            ),
-            id="JSON_WEB_KEY_2020_JWK",
-        ),
-    ],
-)
-def test_create_numalgo_0_malformed_empty_inception_key(ver_material):
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_0(inception_key=ver_material)
-
-
-def test_create_numalgo_0_malformed_empty_inception_key_multibase():
-    ver_material = VerificationMaterialAuthentication(
-        value="",
-        type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-        format=VerificationMaterialFormatPeerDID.MULTIBASE,
-    )
-    with pytest.raises(
-        ValueError, match=r"Invalid key: No transform part in multibase encoding"
-    ):
-        create_peer_did_numalgo_0(inception_key=ver_material)
-
-
-@pytest.mark.parametrize(
-    "ver_material",
-    [
-        pytest.param(
-            VerificationMaterialAgreement(
-                value="ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7",
-                type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-                format=VerificationMaterialFormatPeerDID.BASE58,
+            X25519KeyAgreementKey.from_base58(
+                "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
             ),
             id="X25519_KEY_AGREEMENT_KEY_2019_BASE58",
         ),
         pytest.param(
-            VerificationMaterialAgreement(
-                value="z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.MULTIBASE,
+            X25519KeyAgreementKey.from_multibase(
+                "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
             ),
-            id="X25519_KEY_AGREEMENT_KEY_2019_MILTIBASE",
+            id="X25519_KEY_AGREEMENT_KEY_2019_MULTIBASE",
         ),
         pytest.param(
-            VerificationMaterialAgreement(
-                value={
+            X25519KeyAgreementKey.from_jwk(
+                {
                     "kty": "OKP",
                     "crv": "X25519",
                     "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA",
-                },
-                type=VerificationMethodTypeAgreement.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
+                }
             ),
             id="JSON_WEB_KEY_2020_JWK",
         ),
     ],
 )
 def test_create_numalgo_0_invalid_inception_key_type(ver_material):
-    with pytest.raises(TypeError, match=r"Invalid verification material type"):
+    with pytest.raises(ValueError, match=r"Authentication not supported for key"):
         create_peer_did_numalgo_0(inception_key=ver_material)
diff --git a/tests/test_create_peer_did_numalgo_2.py b/tests/test_create_peer_did_numalgo_2.py
index 3917c6c..ba4e1f8 100644
--- a/tests/test_create_peer_did_numalgo_2.py
+++ b/tests/test_create_peer_did_numalgo_2.py
@@ -1,87 +1,48 @@
-import json
-
 import pytest
 
-from peerdid.peer_did import create_peer_did_numalgo_2, is_peer_did
-from peerdid.types import (
-    VerificationMaterialAgreement,
-    VerificationMethodTypeAgreement,
-    VerificationMaterialAuthentication,
-    VerificationMaterialFormatPeerDID,
-    VerificationMethodTypeAuthentication,
-)
+from peerdid.dids import create_peer_did_numalgo_2, is_peer_did
+from peerdid.keys import Ed25519VerificationKey, X25519KeyAgreementKey
 
-VALID_X25519_KEY_AGREEMENT_KEY_2019 = VerificationMaterialAgreement(
-    value="JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr",
-    type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-    format=VerificationMaterialFormatPeerDID.BASE58,
+VALID_X25519_KEY_AGREEMENT_KEY_2019 = X25519KeyAgreementKey.from_base58(
+    "JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr"
 )
-VALID_X25519_KEY_AGREEMENT_KEY_2020 = VerificationMaterialAgreement(
-    value="z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-    type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2020,
-    format=VerificationMaterialFormatPeerDID.MULTIBASE,
+VALID_X25519_KEY_AGREEMENT_KEY_2020 = X25519KeyAgreementKey.from_multibase(
+    "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
 )
-VALID_AGREEM_JSON_WEB_KEY_2020_DICT = VerificationMaterialAgreement(
-    value={
+VALID_X25519_KEY_AGREEMENT_KEY_JWK = X25519KeyAgreementKey.from_jwk(
+    {
         "kty": "OKP",
         "crv": "X25519",
         "x": "BIiFcQEn3dfvB2pjlhOQQour6jXy9d5s2FKEJNTOJik",
-    },
-    type=VerificationMethodTypeAgreement.JSON_WEB_KEY_2020,
-    format=VerificationMaterialFormatPeerDID.JWK,
-)
-VALID_AGREEM_JSON_WEB_KEY_2020_JSON = VerificationMaterialAgreement(
-    value=json.dumps(
-        {
-            "kty": "OKP",
-            "crv": "X25519",
-            "x": "BIiFcQEn3dfvB2pjlhOQQour6jXy9d5s2FKEJNTOJik",
-        }
-    ),
-    type=VerificationMethodTypeAgreement.JSON_WEB_KEY_2020,
-    format=VerificationMaterialFormatPeerDID.JWK,
+    }
 )
 
-VALID_ED25519_VERIFICATION_KEY_2018_1 = VerificationMaterialAuthentication(
-    value="ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7",
-    type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-    format=VerificationMaterialFormatPeerDID.BASE58,
+VALID_ED25519_VERIFICATION_KEY_2018_1 = Ed25519VerificationKey.from_base58(
+    "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
 )
-VALID_ED25519_VERIFICATION_KEY_2020_1 = VerificationMaterialAuthentication(
-    value="z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-    type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-    format=VerificationMaterialFormatPeerDID.MULTIBASE,
+VALID_ED25519_VERIFICATION_KEY_2020_1 = Ed25519VerificationKey.from_multibase(
+    "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
 )
-VALID_AUTH_JSON_WEB_KEY_2020_1 = VerificationMaterialAuthentication(
-    value={
+VALID_ED25519_VERIFICATION_KEY_JWK_1 = Ed25519VerificationKey.from_jwk(
+    {
         "kty": "OKP",
         "crv": "Ed25519",
         "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA",
     },
-    type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-    format=VerificationMaterialFormatPeerDID.JWK,
 )
 
-VALID_ED25519_VERIFICATION_KEY_2018_2 = VerificationMaterialAuthentication(
-    value="3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J",
-    type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-    format=VerificationMaterialFormatPeerDID.BASE58,
+VALID_ED25519_VERIFICATION_KEY_2018_2 = Ed25519VerificationKey.from_base58(
+    "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
 )
-VALID_ED25519_VERIFICATION_KEY_2020_2 = VerificationMaterialAuthentication(
-    value="z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg",
-    type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-    format=VerificationMaterialFormatPeerDID.MULTIBASE,
+VALID_ED25519_VERIFICATION_KEY_2020_2 = Ed25519VerificationKey.from_multibase(
+    "z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg"
 )
-VALID_AUTH_JSON_WEB_KEY_2020_2 = VerificationMaterialAuthentication(
-    value=json.dumps(
-        {
-            "kty": "OKP",
-            "crv": "Ed25519",
-            "x": "Itv8B__b1-Jos3LCpUe8EdTFGTCa_Dza6_3848P3R70",
-        }
-    ),
-    type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-    format=VerificationMaterialFormatPeerDID.JWK,
+VALID_ED25519_VERIFICATION_KEY_JWK_2 = Ed25519VerificationKey.from_jwk(
+    {
+        "kty": "OKP",
+        "crv": "Ed25519",
+        "x": "Itv8B__b1-Jos3LCpUe8EdTFGTCa_Dza6_3848P3R70",
+    }
 )
 
 VALID_SERVICE = """
@@ -114,14 +75,12 @@
             id="MULTIBASE",
         ),
         pytest.param(
-            [VALID_AGREEM_JSON_WEB_KEY_2020_JSON],
-            [VALID_AUTH_JSON_WEB_KEY_2020_1, VALID_AUTH_JSON_WEB_KEY_2020_2],
-            id="JWK_JSON",
-        ),
-        pytest.param(
-            [VALID_AGREEM_JSON_WEB_KEY_2020_DICT],
-            [VALID_AUTH_JSON_WEB_KEY_2020_1, VALID_AUTH_JSON_WEB_KEY_2020_2],
-            id="JWK_DICT",
+            [VALID_X25519_KEY_AGREEMENT_KEY_JWK],
+            [
+                VALID_ED25519_VERIFICATION_KEY_JWK_1,
+                VALID_ED25519_VERIFICATION_KEY_JWK_2,
+            ],
+            id="JWK",
         ),
     ],
 )
@@ -236,7 +195,10 @@ def test_create_numalgo_2_service_1_element_array():
         ),
         pytest.param(
             [],
-            [VALID_AUTH_JSON_WEB_KEY_2020_1, VALID_AUTH_JSON_WEB_KEY_2020_2],
+            [
+                VALID_ED25519_VERIFICATION_KEY_JWK_1,
+                VALID_ED25519_VERIFICATION_KEY_JWK_2,
+            ],
             id="JWK",
         ),
     ],
@@ -261,7 +223,7 @@ def test_create_numalgo_2_without_encryption_keys(encryption_keys, signing_keys)
     [
         pytest.param([VALID_X25519_KEY_AGREEMENT_KEY_2019], [], id="BASE58"),
         pytest.param([VALID_X25519_KEY_AGREEMENT_KEY_2020], [], id="MULTIBASE"),
-        pytest.param([VALID_AGREEM_JSON_WEB_KEY_2020_JSON], [], id="JWK"),
+        pytest.param([VALID_X25519_KEY_AGREEMENT_KEY_JWK], [], id="JWK"),
     ],
 )
 def test_create_numalgo_2_without_signing_keys(encryption_keys, signing_keys):
@@ -278,92 +240,6 @@ def test_create_numalgo_2_without_signing_keys(encryption_keys, signing_keys):
     assert is_peer_did(peer_did_algo_2)
 
 
-@pytest.mark.parametrize(
-    "encryption_keys, signing_keys",
-    [
-        pytest.param(
-            [
-                VerificationMaterialAgreement(
-                    value="....",
-                    type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-                    format=VerificationMaterialFormatPeerDID.BASE58,
-                )
-            ],
-            [
-                VALID_ED25519_VERIFICATION_KEY_2018_1,
-                VALID_ED25519_VERIFICATION_KEY_2018_2,
-            ],
-            id="BASE58",
-        ),
-        pytest.param(
-            [
-                VerificationMaterialAgreement(
-                    value="z....",
-                    type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2020,
-                    format=VerificationMaterialFormatPeerDID.MULTIBASE,
-                )
-            ],
-            [
-                VALID_ED25519_VERIFICATION_KEY_2020_1,
-                VALID_ED25519_VERIFICATION_KEY_2020_2,
-            ],
-            id="MULTIBASE",
-        ),
-    ],
-)
-def test_create_numalgo_2_wrong_encryption_key_base58(encryption_keys, signing_keys):
-    service = VALID_SERVICE
-
-    with pytest.raises(ValueError, match=r"Invalid key: Invalid base58 encoding"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_wrong_jwk():
-    encryption_keys = [
-        VerificationMaterialAgreement(
-            value={"kty": "OKP", "crv": "X25519", "x": "..."},
-            type=VerificationMethodTypeAgreement.JSON_WEB_KEY_2020,
-            format=VerificationMaterialFormatPeerDID.JWK,
-        )
-    ]
-    signing_keys = [VALID_AUTH_JSON_WEB_KEY_2020_1, VALID_AUTH_JSON_WEB_KEY_2020_2]
-    service = VALID_SERVICE
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_wrong_signing_key():
-    encryption_keys = [
-        VerificationMaterialAgreement(
-            value="6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    signing_keys = [
-        VerificationMaterialAuthentication(
-            value=".......",
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        ),
-        VerificationMaterialAuthentication(
-            value="zx8xB2pv7cw8q1PdDacSrdWE3dtB9f7Nxk886mdzNFoPtY",
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        ),
-    ]
-    service = VALID_SERVICE
-
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
 def test_create_numalgo_2_wrong_service():
     encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
     signing_keys = [
@@ -372,7 +248,7 @@ def test_create_numalgo_2_wrong_service():
     ]
     service = "......."
 
-    with pytest.raises(ValueError, match=r"Service is not a valid JSON"):
+    with pytest.raises(ValueError, match=r"Service is not valid JSON"):
         create_peer_did_numalgo_2(
             encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
         )
@@ -381,7 +257,7 @@ def test_create_numalgo_2_wrong_service():
 def test_create_numalgo_2_encryption_key_as_signing():
     encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
     service = VALID_SERVICE
-    with pytest.raises(TypeError, match=r"Invalid verification material type"):
+    with pytest.raises(ValueError, match=r"Authentication not supported for key"):
         create_peer_did_numalgo_2(
             encryption_keys=encryption_keys,
             signing_keys=encryption_keys,
@@ -395,13 +271,13 @@ def test_create_numalgo_2_signing_key_as_encryption():
         VALID_ED25519_VERIFICATION_KEY_2018_2,
     ]
     service = VALID_SERVICE
-    with pytest.raises(TypeError, match=r"Invalid verification material type"):
+    with pytest.raises(ValueError, match=r"Key agreement not supported for key"):
         create_peer_did_numalgo_2(
             encryption_keys=signing_keys, signing_keys=signing_keys, service=service
         )
 
 
-def test_create_numalgo_2_service_is_None():
+def test_create_numalgo_2_service_is_none():
     encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
     signing_keys = [
         VALID_ED25519_VERIFICATION_KEY_2018_1,
@@ -436,7 +312,7 @@ def test_create_numalgo_2_encryption_and_signing_keys_are_more_than_1_element_ar
     encryption_keys = [
         VALID_X25519_KEY_AGREEMENT_KEY_2019,
         VALID_X25519_KEY_AGREEMENT_KEY_2020,
-        VALID_AGREEM_JSON_WEB_KEY_2020_DICT,
+        VALID_X25519_KEY_AGREEMENT_KEY_JWK,
     ]
     signing_keys = [
         VALID_ED25519_VERIFICATION_KEY_2018_1,
@@ -498,10 +374,10 @@ def test_create_numalgo_2_service_is_empty_string():
     ]
     service = ""
 
-    with pytest.raises(ValueError, match=r"Service is not a valid JSON"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
+    peer_did_algo_2 = create_peer_did_numalgo_2(
+        encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
+    )
+    assert is_peer_did(peer_did_algo_2)
 
 
 def test_create_numalgo_2_service_is_empty_array():
@@ -512,10 +388,10 @@ def test_create_numalgo_2_service_is_empty_array():
     ]
     service = []
 
-    with pytest.raises(ValueError, match=r"Service is not a valid JSON"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
+    peer_did_algo_2 = create_peer_did_numalgo_2(
+        encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
+    )
+    assert is_peer_did(peer_did_algo_2)
 
 
 def test_create_numalgo_2_different_types_of_service():
@@ -543,198 +419,3 @@ def test_create_numalgo_2_different_types_of_service():
         encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
     )
     assert is_peer_did(peer_did_algo_2)
-
-
-def test_create_numalgo_2_malformed_encryption_key_not_base58_encoded():
-    encryption_keys = [
-        VerificationMaterialAgreement(
-            value="JhNWeSVLMYcc0k7iopQW4guaSJTojqpMEELgSLhKwRr",
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    signing_keys = [
-        VALID_ED25519_VERIFICATION_KEY_2018_1,
-        VALID_ED25519_VERIFICATION_KEY_2018_2,
-    ]
-    service = """{
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint",
-            "routingKeys": ["did:example:somemediator#somekey"]
-            }
-            """
-    with pytest.raises(ValueError, match=r"Invalid key: Invalid base58 encoding"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_malformed_short_encryption_key():
-    encryption_keys = [
-        VerificationMaterialAgreement(
-            value="JhNWeSV",
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    signing_keys = [
-        VALID_ED25519_VERIFICATION_KEY_2018_1,
-        VALID_ED25519_VERIFICATION_KEY_2018_2,
-    ]
-    service = """{
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint",
-            "routingKeys": ["did:example:somemediator#somekey"]
-            }
-            """
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_malformed_long_encryption_key():
-    encryption_keys = [
-        VerificationMaterialAgreement(
-            value="JhNWeSVJhNWeSVJhNWeSVJhNWeSVJhNWeSVJhNWeSVJhNWeSVJhNWeSVJhNWe",
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    signing_keys = [
-        VALID_ED25519_VERIFICATION_KEY_2018_1,
-        VALID_ED25519_VERIFICATION_KEY_2018_2,
-    ]
-    service = """{
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint",
-            "routingKeys": ["did:example:somemediator#somekey"]
-            }
-            """
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_malformed_encryption_key_empty():
-    encryption_keys = [
-        VerificationMaterialAgreement(
-            value="",
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    signing_keys = [
-        VALID_ED25519_VERIFICATION_KEY_2018_1,
-        VALID_ED25519_VERIFICATION_KEY_2018_2,
-    ]
-    service = """{
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint",
-            "routingKeys": ["did:example:somemediator#somekey"]
-            }
-            """
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_invalid_encryption_key_type():
-    encryption_keys = [VALID_ED25519_VERIFICATION_KEY_2018_1]
-    signing_keys = [
-        VALID_ED25519_VERIFICATION_KEY_2018_1,
-        VALID_ED25519_VERIFICATION_KEY_2018_2,
-    ]
-    service = VALID_SERVICE
-
-    with pytest.raises(TypeError, match=r"Invalid verification material type"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_malformed_signing_key_not_base58_encoded():
-    encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
-    signing_keys = [
-        VerificationMaterialAuthentication(
-            value="3M5RCDjPTWPkKSN3sxU0mMqHbmRPegYP1tjcKyrDbt9J",
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    service = VALID_SERVICE
-
-    with pytest.raises(ValueError, match=r"Invalid key: Invalid base58 encoding"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_malformed_short_signing_key():
-    encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
-    signing_keys = [
-        VerificationMaterialAuthentication(
-            value="ByHnpUCF",
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    service = VALID_SERVICE
-
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_malformed_long_signing_key():
-    encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
-    signing_keys = [
-        VerificationMaterialAuthentication(
-            value="3M5RCDjxUmmMqHbmRPegYPPTWPkKSN3sxUmmMqHbmRPegYPxUmmMqHbmRPegYP1tjcKxUmmMqHbmRPegYPyrDbt9J",
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    service = VALID_SERVICE
-
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_malformed_empty_signing_key():
-    encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
-    signing_keys = [
-        VerificationMaterialAuthentication(
-            value="",
-            type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    service = VALID_SERVICE
-
-    with pytest.raises(ValueError, match=r"Invalid key"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
-
-
-def test_create_numalgo_2_invalid_inception_key_type():
-    encryption_keys = [VALID_X25519_KEY_AGREEMENT_KEY_2019]
-    signing_keys = [
-        VerificationMaterialAgreement(
-            value="ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7",
-            type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            format=VerificationMaterialFormatPeerDID.BASE58,
-        )
-    ]
-    service = VALID_SERVICE
-
-    with pytest.raises(TypeError, match=r"Invalid verification material type"):
-        create_peer_did_numalgo_2(
-            encryption_keys=encryption_keys, signing_keys=signing_keys, service=service
-        )
diff --git a/tests/test_did_doc.py b/tests/test_did_doc.py
deleted file mode 100644
index bed737d..0000000
--- a/tests/test_did_doc.py
+++ /dev/null
@@ -1,413 +0,0 @@
-import json
-
-import pytest
-
-from peerdid.core.did_doc_types import (
-    VerificationMethodField,
-    DIDCommServicePeerDID,
-)
-from peerdid.did_doc import DIDDocPeerDID
-from peerdid.errors import MalformedPeerDIDDocError
-from peerdid.types import (
-    VerificationMaterialFormatPeerDID,
-    VerificationMethodTypeAuthentication,
-    VerificationMethodTypeAgreement,
-)
-from tests.test_vectors import (
-    DID_DOC_NUMALGO_O_BASE58,
-    DID_DOC_NUMALGO_O_MULTIBASE,
-    DID_DOC_NUMALGO_O_JWK,
-    DID_DOC_NUMALGO_2_BASE58,
-    DID_DOC_NUMALGO_2_MULTIBASE,
-    DID_DOC_NUMALGO_2_JWK,
-    PEER_DID_NUMALGO_0,
-    PEER_DID_NUMALGO_2,
-    DID_DOC_NUMALGO_2_MULTIBASE_2_SERVICES,
-    PEER_DID_NUMALGO_2_2_SERVICES,
-    DID_DOC_NUMALGO_2_MULTIBASE_NO_SERVICES,
-    PEER_DID_NUMALGO_2_NO_SERVICES,
-    PEER_DID_NUMALGO_2_MINIMAL_SERVICES,
-    DID_DOC_NUMALGO_2_MULTIBASE_MINIMAL_SERVICES,
-)
-
-
-@pytest.mark.parametrize(
-    "did_doc_json, expected_format, expected_field, expected_type",
-    [
-        pytest.param(
-            DID_DOC_NUMALGO_O_BASE58,
-            VerificationMaterialFormatPeerDID.BASE58,
-            VerificationMethodField.BASE58,
-            VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            id="numalgo_0_base58",
-        ),
-        pytest.param(
-            DID_DOC_NUMALGO_O_MULTIBASE,
-            VerificationMaterialFormatPeerDID.MULTIBASE,
-            VerificationMethodField.MULTIBASE,
-            VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-            id="numalgo_0_multibase",
-        ),
-        pytest.param(
-            DID_DOC_NUMALGO_O_JWK,
-            VerificationMaterialFormatPeerDID.JWK,
-            VerificationMethodField.JWK,
-            VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-            id="numalgo_0_jwk",
-        ),
-    ],
-)
-def test_did_doc_from_json_numalgo_0(
-    did_doc_json, expected_format, expected_field, expected_type
-):
-    did_doc = DIDDocPeerDID.from_json(did_doc_json)
-
-    assert isinstance(did_doc, DIDDocPeerDID)
-    assert did_doc.did == PEER_DID_NUMALGO_0
-
-    assert did_doc.key_agreement == []
-    assert did_doc.service is None
-    assert len(did_doc.authentication) == 1
-
-    auth = did_doc.authentication[0]
-    expected_auth = json.loads(did_doc_json)["authentication"][0]
-    assert auth.id == expected_auth["id"]
-    assert auth.controller == PEER_DID_NUMALGO_0
-    assert auth.ver_material.format == expected_format
-    assert auth.ver_material.type == expected_type
-    assert auth.ver_material.value == expected_auth[expected_field.value]
-
-    assert did_doc.auth_kids == [expected_auth["id"]]
-    assert did_doc.agreement_kids == []
-
-
-@pytest.mark.parametrize(
-    "did_doc_json, expected_format, expected_field, expected_auth_type, expected_agreem_type",
-    [
-        pytest.param(
-            DID_DOC_NUMALGO_2_BASE58,
-            VerificationMaterialFormatPeerDID.BASE58,
-            VerificationMethodField.BASE58,
-            VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-            VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-            id="numalgo_2_base58",
-        ),
-        pytest.param(
-            DID_DOC_NUMALGO_2_MULTIBASE,
-            VerificationMaterialFormatPeerDID.MULTIBASE,
-            VerificationMethodField.MULTIBASE,
-            VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-            VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2020,
-            id="numalgo_2_multibase",
-        ),
-        pytest.param(
-            DID_DOC_NUMALGO_2_JWK,
-            VerificationMaterialFormatPeerDID.JWK,
-            VerificationMethodField.JWK,
-            VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-            VerificationMethodTypeAgreement.JSON_WEB_KEY_2020,
-            id="numalgo_2_jwk",
-        ),
-    ],
-)
-def test_did_doc_from_json_numalgo_2(
-    did_doc_json,
-    expected_format,
-    expected_field,
-    expected_auth_type,
-    expected_agreem_type,
-):
-    did_doc = DIDDocPeerDID.from_json(did_doc_json)
-
-    assert isinstance(did_doc, DIDDocPeerDID)
-    assert did_doc.did == PEER_DID_NUMALGO_2
-
-    assert len(did_doc.key_agreement) == 1
-    assert len(did_doc.authentication) == 2
-
-    auth = did_doc.authentication[0]
-    expected_auth = json.loads(did_doc_json)["authentication"][0]
-    assert auth.id == expected_auth["id"]
-    assert auth.controller == PEER_DID_NUMALGO_2
-    assert auth.ver_material.format == expected_format
-    assert auth.ver_material.type == expected_auth_type
-    assert auth.ver_material.value == expected_auth[expected_field.value]
-
-    agreement = did_doc.key_agreement[0]
-    expected_agreement = json.loads(did_doc_json)["keyAgreement"][0]
-    assert agreement.id == expected_agreement["id"]
-    assert agreement.controller == PEER_DID_NUMALGO_2
-    assert agreement.ver_material.format == expected_format
-    assert agreement.ver_material.type == expected_agreem_type
-    assert agreement.ver_material.value == expected_agreement[expected_field.value]
-
-    services = did_doc.service
-    expected_service = json.loads(did_doc_json)["service"][0]
-    assert services is not None
-    assert len(services) == 1
-    service = services[0]
-    assert isinstance(service, DIDCommServicePeerDID)
-    assert service.id == expected_service["id"]
-    assert service.service_endpoint == expected_service["serviceEndpoint"]
-    assert service.routing_keys == expected_service["routingKeys"]
-    assert service.accept == expected_service["accept"]
-
-    assert did_doc.auth_kids == [
-        v["id"] for v in json.loads(did_doc_json)["authentication"]
-    ]
-    assert did_doc.agreement_kids == [expected_agreement["id"]]
-
-
-def test_did_doc_from_json_numalgo_2_service_2_elements():
-    did_doc = DIDDocPeerDID.from_json(DID_DOC_NUMALGO_2_MULTIBASE_2_SERVICES)
-
-    assert isinstance(did_doc, DIDDocPeerDID)
-    assert did_doc.did == PEER_DID_NUMALGO_2_2_SERVICES
-
-    services = did_doc.service
-    assert services is not None
-    assert len(services) == 2
-
-    service_1 = services[0]
-    expected_service_1 = json.loads(DID_DOC_NUMALGO_2_MULTIBASE_2_SERVICES)["service"][
-        0
-    ]
-    assert isinstance(service_1, DIDCommServicePeerDID)
-    assert service_1.id == expected_service_1["id"]
-    assert service_1.service_endpoint == expected_service_1["serviceEndpoint"]
-    assert service_1.routing_keys == expected_service_1["routingKeys"]
-    assert service_1.accept == []
-
-    service_2 = services[1]
-    expected_service_2 = json.loads(DID_DOC_NUMALGO_2_MULTIBASE_2_SERVICES)["service"][
-        1
-    ]
-    assert isinstance(service_2, dict)
-    assert service_2 == expected_service_2
-
-
-def test_did_doc_from_json_numalgo_2_no_service():
-    did_doc = DIDDocPeerDID.from_json(DID_DOC_NUMALGO_2_MULTIBASE_NO_SERVICES)
-
-    assert isinstance(did_doc, DIDDocPeerDID)
-    assert did_doc.did == PEER_DID_NUMALGO_2_NO_SERVICES
-
-    assert len(did_doc.key_agreement) == 1
-    assert len(did_doc.authentication) == 1
-    assert did_doc.service is None
-
-
-def test_did_doc_from_json_numalgo_2_minimal_service():
-    did_doc = DIDDocPeerDID.from_json(DID_DOC_NUMALGO_2_MULTIBASE_MINIMAL_SERVICES)
-
-    assert isinstance(did_doc, DIDDocPeerDID)
-    assert did_doc.did == PEER_DID_NUMALGO_2_MINIMAL_SERVICES
-
-    assert len(did_doc.key_agreement) == 1
-    assert len(did_doc.authentication) == 2
-    assert did_doc.service is not None
-    assert len(did_doc.service) == 1
-
-    service = did_doc.service[0]
-    expected_service = json.loads(DID_DOC_NUMALGO_2_MULTIBASE_MINIMAL_SERVICES)[
-        "service"
-    ][0]
-    assert isinstance(service, DIDCommServicePeerDID)
-    assert service.id == expected_service["id"]
-    assert service.service_endpoint == expected_service["serviceEndpoint"]
-    assert service.routing_keys == []
-    assert service.accept == []
-
-
-def test_did_doc_id_only():
-    didDoc = DIDDocPeerDID.from_json(
-        """
-   {
-       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-   }
-            """
-    )
-    assert didDoc.did == "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-
-
-def test_did_doc_invalid_json():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*Invalid JSON",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-            sdfasdfsf{sdfsdfasdf...
-            """
-        )
-
-
-def test_did_doc_from_invalid_json_no_id():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*No 'id' field",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "authentication": [
-                           {
-                               "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "type": "Ed25519VerificationKey2020",
-                               "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                           }
-                       ]
-                   }
-                """
-        )
-
-
-def test_did_doc_from_invalid_ver_method_no_id():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*No 'id' field in method",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                       "authentication": [
-                           {
-                               "type": "Ed25519VerificationKey2020",
-                               "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                           }
-                       ]
-                   }
-                """
-        )
-
-
-def test_did_doc_from_invalid_ver_method_no_type():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*No 'type' field in method",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                       "authentication": [
-                           {
-                               "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                           }
-                       ]
-                   }
-                """
-        )
-
-
-def test_did_doc_from_invalid_ver_method_no_controller():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*No 'controller' field in method",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                       "authentication": [
-                           {
-                               "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "type": "Ed25519VerificationKey2020",
-                               "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                           }
-                       ]
-                   }
-                """
-        )
-
-
-def test_did_doc_from_invalid_ver_method_no_value():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*No public key field",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                       "authentication": [
-                           {
-                               "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "type": "Ed25519VerificationKey2020",
-                               "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                           }
-                       ]
-                   }
-                """
-        )
-
-
-def test_did_doc_from_invalid_ver_method_invalid_type():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*Unknown verification method type",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                       "authentication": [
-                           {
-                               "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "type": "Unkknown",
-                               "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                           }
-                       ]
-                   }
-                """
-        )
-
-
-def test_did_doc_from_invalid_ver_method_invalid_field():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*No public key field",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                       "authentication": [
-                           {
-                               "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "type": "Ed25519VerificationKey2020",
-                               "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "publicKeyJwk": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                           }
-                       ]
-                   }
-                """
-        )
-
-
-def test_did_doc_from_invalid_ver_method_invalid_value_jwk():
-    with pytest.raises(
-        MalformedPeerDIDDocError,
-        match=r"Invalid peer DID Doc.*No 'crv' field in JWK",
-    ):
-        DIDDocPeerDID.from_json(
-            """
-                   {
-                       "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                       "authentication": [
-                           {
-                               "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "type": "JsonWebKey2020",
-                               "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                               "publicKeyJwk": "sdfsdf{sfsdfdf"
-                           }
-                       ]
-                   }
-                """
-        )
diff --git a/tests/test_peer_did_helpers.py b/tests/test_peer_did_helpers.py
index 236ee1d..c70a9e6 100644
--- a/tests/test_peer_did_helpers.py
+++ b/tests/test_peer_did_helpers.py
@@ -1,20 +1,17 @@
 import pytest
 
-from peerdid.core.did_doc_types import (
-    VerificationMethodTypeAgreement,
-    VerificationMethodTypeAuthentication,
-)
+from pydid import Service
+
 from peerdid.core.peer_did_helper import (
     encode_service,
     decode_service,
-    decode_multibase_encnumbasis,
+    decode_multibase_numbasis,
 )
-from peerdid.types import (
-    VerificationMaterialFormatPeerDID,
-    VerificationMaterialAuthentication,
-    VerificationMaterialAgreement,
+from peerdid.keys import (
+    Ed25519VerificationKey,
+    X25519KeyAgreementKey,
+    KeyFormat,
 )
-from tests.test_vectors import PEER_DID_NUMALGO_2
 
 
 def test_encode_service():
@@ -35,16 +32,17 @@ def test_encode_service():
 def test_decode_service():
     service = decode_service(
         service="eyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-        peer_did=PEER_DID_NUMALGO_2,
     )
     expected = [
-        {
-            "id": PEER_DID_NUMALGO_2 + "#didcommmessaging-0",
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint",
-            "routingKeys": ["did:example:somemediator#somekey"],
-            "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
-        }
+        Service.deserialize(
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+                "routingKeys": ["did:example:somemediator#somekey"],
+                "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+            }
+        )
     ]
     assert service == expected
 
@@ -64,34 +62,35 @@ def test_encode_service_minimal_fields():
 def test_decode_service_minimal_fields():
     service = decode_service(
         service="eyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
-        peer_did=PEER_DID_NUMALGO_2,
     )
     expected = [
-        {
-            "id": PEER_DID_NUMALGO_2 + "#didcommmessaging-0",
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint",
-        }
+        Service.deserialize(
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+            }
+        )
     ]
     assert service == expected
 
 
 def test_encode_service_with_multiple_entries_list():
     services = """
-            [
-                {
-                    "type": "DIDCommMessaging",
-                    "serviceEndpoint": "https://example.com/endpoint",
-                    "routingKeys": ["did:example:somemediator#somekey"],
-                    "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"]
-                },
-                {
-                    "type": "DIDCommMessaging",
-                    "serviceEndpoint": "https://example.com/endpoint2",
-                    "routingKeys": ["did:example:somemediator#somekey2"]
-                }
-            ]
-            """
+        [
+            {
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+                "routingKeys": ["did:example:somemediator#somekey"],
+                "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"]
+            },
+            {
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint2",
+                "routingKeys": ["did:example:somemediator#somekey2"]
+            }
+        ]
+        """
 
     encoded_services = encode_service(services)
     assert (
@@ -103,22 +102,25 @@ def test_encode_service_with_multiple_entries_list():
 def test_decode_service_with_multiple_entries_list():
     service = decode_service(
         service="W3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il0sImEiOlsiZGlkY29tbS92MiIsImRpZGNvbW0vYWlwMjtlbnY9cmZjNTg3Il19LHsidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQyIiwiciI6WyJkaWQ6ZXhhbXBsZTpzb21lbWVkaWF0b3Ijc29tZWtleTIiXX1d",
-        peer_did=PEER_DID_NUMALGO_2,
     )
     expected = [
-        {
-            "id": PEER_DID_NUMALGO_2 + "#didcommmessaging-0",
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint",
-            "routingKeys": ["did:example:somemediator#somekey"],
-            "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
-        },
-        {
-            "id": PEER_DID_NUMALGO_2 + "#didcommmessaging-1",
-            "type": "DIDCommMessaging",
-            "serviceEndpoint": "https://example.com/endpoint2",
-            "routingKeys": ["did:example:somemediator#somekey2"],
-        },
+        Service.deserialize(
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+                "routingKeys": ["did:example:somemediator#somekey"],
+                "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+            }
+        ),
+        Service.deserialize(
+            {
+                "id": "#didcommmessaging-1",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint2",
+                "routingKeys": ["did:example:somemediator#somekey2"],
+            }
+        ),
     ]
     assert service == expected
 
@@ -128,65 +130,53 @@ def test_decode_service_with_multiple_entries_list():
     [
         pytest.param(
             "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-            VerificationMaterialFormatPeerDID.BASE58,
-            VerificationMaterialAuthentication(
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2018,
-                format=VerificationMaterialFormatPeerDID.BASE58,
-                value="ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7",
+            KeyFormat.BASE58,
+            Ed25519VerificationKey.from_base58(
+                "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
             ),
             id="base58-ed25519",
         ),
         pytest.param(
             "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-            VerificationMaterialFormatPeerDID.BASE58,
-            VerificationMaterialAgreement(
-                type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2019,
-                format=VerificationMaterialFormatPeerDID.BASE58,
-                value="JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr",
+            KeyFormat.BASE58,
+            X25519KeyAgreementKey.from_base58(
+                "JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr"
             ),
             id="base58-x25519",
         ),
         pytest.param(
             "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-            VerificationMaterialFormatPeerDID.MULTIBASE,
-            VerificationMaterialAuthentication(
-                type=VerificationMethodTypeAuthentication.ED25519_VERIFICATION_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.MULTIBASE,
-                value="z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+            KeyFormat.MULTIBASE,
+            Ed25519VerificationKey.from_multibase(
+                "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
             ),
             id="multibase-ed25519",
         ),
         pytest.param(
             "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-            VerificationMaterialFormatPeerDID.MULTIBASE,
-            VerificationMaterialAgreement(
-                type=VerificationMethodTypeAgreement.X25519_KEY_AGREEMENT_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.MULTIBASE,
-                value="z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
+            KeyFormat.MULTIBASE,
+            X25519KeyAgreementKey.from_multibase(
+                "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ),
             id="multibase-x25519",
         ),
         pytest.param(
             "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-            VerificationMaterialFormatPeerDID.JWK,
-            VerificationMaterialAuthentication(
-                type=VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
-                value={
+            KeyFormat.JWK,
+            Ed25519VerificationKey.from_jwk(
+                {
                     "kty": "OKP",
                     "crv": "Ed25519",
                     "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA",
-                },
+                }
             ),
             id="jwk-ed25519",
         ),
         pytest.param(
             "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-            VerificationMaterialFormatPeerDID.JWK,
-            VerificationMaterialAgreement(
-                type=VerificationMethodTypeAgreement.JSON_WEB_KEY_2020,
-                format=VerificationMaterialFormatPeerDID.JWK,
-                value={
+            KeyFormat.JWK,
+            X25519KeyAgreementKey.from_jwk(
+                {
                     "kty": "OKP",
                     "crv": "X25519",
                     "x": "BIiFcQEn3dfvB2pjlhOQQour6jXy9d5s2FKEJNTOJik",
@@ -196,6 +186,6 @@ def test_decode_service_with_multiple_entries_list():
         ),
     ],
 )
-def test_decode_encumbasis(input_multibase, format, expected):
-    res = decode_multibase_encnumbasis(input_multibase, format)
-    assert res.ver_material == expected
+def test_decode_numbasis(input_multibase, format, expected):
+    res = decode_multibase_numbasis(input_multibase, format)
+    assert res == expected
diff --git a/tests/test_resolve_peer_did_numalgo_0.py b/tests/test_resolve_peer_did_numalgo_0.py
index 0e9649a..ccc6cf7 100644
--- a/tests/test_resolve_peer_did_numalgo_0.py
+++ b/tests/test_resolve_peer_did_numalgo_0.py
@@ -1,10 +1,9 @@
-import json
-
 import pytest
 
+from peerdid import DIDDocument
 from peerdid.errors import MalformedPeerDIDError
-from peerdid.peer_did import resolve_peer_did
-from peerdid.types import VerificationMaterialFormatPeerDID
+from peerdid.dids import resolve_peer_did
+from peerdid.keys import KeyFormat
 from tests.test_vectors import (
     PEER_DID_NUMALGO_0,
     DID_DOC_NUMALGO_O_BASE58,
@@ -15,28 +14,22 @@
 
 def test_resolve_positive_default():
     did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_0)
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_O_MULTIBASE)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_O_MULTIBASE)
 
 
 def test_resolve_positive_base58():
-    did_doc = resolve_peer_did(
-        peer_did=PEER_DID_NUMALGO_0, format=VerificationMaterialFormatPeerDID.BASE58
-    )
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_O_BASE58)
+    did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_0, format=KeyFormat.BASE58)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_O_BASE58)
 
 
 def test_resolve_positive_multibase():
-    did_doc = resolve_peer_did(
-        peer_did=PEER_DID_NUMALGO_0, format=VerificationMaterialFormatPeerDID.MULTIBASE
-    )
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_O_MULTIBASE)
+    did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_0, format=KeyFormat.MULTIBASE)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_O_MULTIBASE)
 
 
 def test_resolve_positive_jwk():
-    did_doc = resolve_peer_did(
-        peer_did=PEER_DID_NUMALGO_0, format=VerificationMaterialFormatPeerDID.JWK
-    )
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_O_JWK)
+    did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_0, format=KeyFormat.JWK)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_O_JWK)
 
 
 def test_resolve_unsupported_did_method():
@@ -55,7 +48,7 @@ def test_resolve_invalid_peer_did():
         match=r"Invalid peer DID provided.*Does not match peer DID regexp",
     ):
         resolve_peer_did(
-            peer_did="did:peer:0z6MkqRYqQiSBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+            peer_did="did:peer:0z6MkqRYqQiSBytw86Qbs2ZWUkGv22od935YF4s8M7V!"
         )
 
 
@@ -103,14 +96,14 @@ def test_resolve_numalgo_0_invalid_key_type():
         MalformedPeerDIDError, match=r"Invalid peer DID provided.*Invalid key"
     ):
         resolve_peer_did(
-            peer_did="did:peer:0z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
+            peer_did="did:peer:0z6QSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
         )
 
 
 def test_resolve_numalgo_0_short_key():
     with pytest.raises(
         MalformedPeerDIDError,
-        match=r"Invalid peer DID provided.*Does not match peer DID regexp",
+        match=r"Invalid peer DID provided.*Invalid key",
     ):
         resolve_peer_did(peer_did="did:peer:0z6LSbysY2xc")
 
@@ -118,7 +111,7 @@ def test_resolve_numalgo_0_short_key():
 def test_resolve_numalgo_0_long_key():
     with pytest.raises(
         MalformedPeerDIDError,
-        match=r"Invalid peer DID provided.*Does not match peer DID regexp",
+        match=r"Invalid peer DID provided.*Invalid key",
     ):
         resolve_peer_did(
             peer_did="did:peer:0z6LSbysY2xcccccccccccccccccccccccccccccccccccccccccccccccccccccc"
diff --git a/tests/test_resolve_peer_did_numalgo_2.py b/tests/test_resolve_peer_did_numalgo_2.py
index 1be7813..e52dc1a 100644
--- a/tests/test_resolve_peer_did_numalgo_2.py
+++ b/tests/test_resolve_peer_did_numalgo_2.py
@@ -1,10 +1,9 @@
-import json
-
 import pytest
 
+from peerdid import DIDDocument
 from peerdid.errors import MalformedPeerDIDError
-from peerdid.peer_did import resolve_peer_did
-from peerdid.types import VerificationMaterialFormatPeerDID
+from peerdid.dids import resolve_peer_did
+from peerdid.keys import KeyFormat
 from tests.test_vectors import (
     DID_DOC_NUMALGO_2_BASE58,
     PEER_DID_NUMALGO_2,
@@ -21,43 +20,37 @@
 
 def test_resolve_numalgo_2_positive_default():
     did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_2)
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_2_MULTIBASE)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_2_MULTIBASE)
 
 
 def test_resolve_numalgo_2_positive_base58():
-    did_doc = resolve_peer_did(
-        peer_did=PEER_DID_NUMALGO_2, format=VerificationMaterialFormatPeerDID.BASE58
-    )
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_2_BASE58)
+    did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_2, format=KeyFormat.BASE58)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_2_BASE58)
 
 
 def test_resolve_numalgo_2_positive_multibase():
-    did_doc = resolve_peer_did(
-        peer_did=PEER_DID_NUMALGO_2, format=VerificationMaterialFormatPeerDID.MULTIBASE
-    )
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_2_MULTIBASE)
+    did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_2, format=KeyFormat.MULTIBASE)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_2_MULTIBASE)
 
 
 def test_resolve_numalgo_2_positive_jwk():
-    did_doc = resolve_peer_did(
-        peer_did=PEER_DID_NUMALGO_2, format=VerificationMaterialFormatPeerDID.JWK
-    )
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_2_JWK)
+    did_doc = resolve_peer_did(peer_did=PEER_DID_NUMALGO_2, format=KeyFormat.JWK)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_2_JWK)
 
 
 def test_resolve_numalgo_2_positive_service_is_2_element_array():
     did_doc = resolve_peer_did(PEER_DID_NUMALGO_2_2_SERVICES)
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_2_MULTIBASE_2_SERVICES)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_2_MULTIBASE_2_SERVICES)
 
 
 def test_resolve_numalgo_2_positive_no_service():
     did_doc = resolve_peer_did(PEER_DID_NUMALGO_2_NO_SERVICES)
-    assert json.loads(did_doc) == json.loads(DID_DOC_NUMALGO_2_MULTIBASE_NO_SERVICES)
+    assert did_doc == DIDDocument.from_json(DID_DOC_NUMALGO_2_MULTIBASE_NO_SERVICES)
 
 
 def test_resolve_numalgo_2_positive_minimal_service():
     did_doc = resolve_peer_did(PEER_DID_NUMALGO_2_MINIMAL_SERVICES)
-    assert json.loads(did_doc) == json.loads(
+    assert did_doc == DIDDocument.from_json(
         DID_DOC_NUMALGO_2_MULTIBASE_MINIMAL_SERVICES
     )
 
@@ -70,7 +63,7 @@ def test_resolve_numalgo_2_unsupported_transform_code():
         resolve_peer_did(
             "did:peer:2.Ea6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Va6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
@@ -82,7 +75,7 @@ def test_resolve_numalgo_2_signing_malformed_base58_encoding():
         resolve_peer_did(
             "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Vz6MkqRYqQiSgvZQdnBytw86Qbs0ZWUkGv22od935YF4s8M7V"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
@@ -105,7 +98,7 @@ def test_resolve_numalgo_2_signing_malformed_multicodec_encoding():
         resolve_peer_did(
             "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Vz6666YqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
@@ -116,29 +109,31 @@ def test_resolve_numalgo_2_encryption_malformed_multicodec_encoding():
         resolve_peer_did(
             "did:peer:2.Ez7777sY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
 def test_resolve_numalgo_2_signing_invalid_key_type():
     with pytest.raises(
-        MalformedPeerDIDError, match=r"Invalid peer DID provided.*Invalid key"
+        MalformedPeerDIDError,
+        match=r"Invalid peer DID provided.*Authentication not supported for key",
     ):
         resolve_peer_did(
             "did:peer:2.Vz6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
 def test_resolve_numalgo_2_encryption_invalid_key_type():
     with pytest.raises(
-        MalformedPeerDIDError, match=r"Invalid peer DID provided.*Invalid key"
+        MalformedPeerDIDError,
+        match=r"Invalid peer DID provided.*Key agreement not supported for key",
     ):
         resolve_peer_did(
             "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Ez6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
@@ -178,26 +173,26 @@ def test_resolve_numalgo_2_invalid_prefix():
             "did:peer:2"
             ".Cz6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
 def test_resolve_numalgo_2_short_signing_key():
     with pytest.raises(
         MalformedPeerDIDError,
-        match=r"Invalid peer DID provided.*Does not match peer DID regexp",
+        match=r"Invalid peer DID provided.*Invalid key",
     ):
         resolve_peer_did(
             "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
             ".Vz6MkqRYqQiS"
-            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0="
+            ".SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXX0"
         )
 
 
 def test_resolve_numalgo_2_short_encryption_key():
     with pytest.raises(
         MalformedPeerDIDError,
-        match=r"Invalid peer DID provided.*Does not match peer DID regexp",
+        match=r"Invalid peer DID provided.*Invalid key",
     ):
         resolve_peer_did(
             "did:peer:2"
@@ -211,7 +206,7 @@ def test_resolve_numalgo_2_short_encryption_key():
 def test_resolve_numalgo_2_long_signing_key():
     with pytest.raises(
         MalformedPeerDIDError,
-        match=r"Invalid peer DID provided.*Does not match peer DID regexp",
+        match=r"Invalid peer DID provided.*Invalid key",
     ):
         resolve_peer_did(
             "did:peer:2"
@@ -225,7 +220,7 @@ def test_resolve_numalgo_2_long_signing_key():
 def test_resolve_numalgo_2_long_encryption_key():
     with pytest.raises(
         MalformedPeerDIDError,
-        match=r"Invalid peer DID provided.*Does not match peer DID regexp",
+        match=r"Invalid peer DID provided.*Invalid key",
     ):
         resolve_peer_did(
             "did:peer:2"
diff --git a/tests/test_vectors.py b/tests/test_vectors.py
index 5e6ef86..d8c081f 100644
--- a/tests/test_vectors.py
+++ b/tests/test_vectors.py
@@ -1,49 +1,70 @@
 PEER_DID_NUMALGO_0 = "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
 
 DID_DOC_NUMALGO_O_BASE58 = """
-       {
-           "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-           "authentication": [
-               {
-                   "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "type": "Ed25519VerificationKey2018",
-                   "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "publicKeyBase58": "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
-               }
-           ]
-       }
+    {
+        "@context": ["https://www.w3.org/ns/did/v1"],
+        "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+        "verificationMethod": [
+            {
+                "id": "#6MkqRYqQ",
+                "type": "Ed25519VerificationKey2018",
+                "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+                "publicKeyBase58": "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
+            }
+        ],
+        "authentication": ["#6MkqRYqQ"],
+        "assertionMethod": ["#6MkqRYqQ"],
+        "capabilityInvocation": ["#6MkqRYqQ"],
+        "capabilityDelegation": ["#6MkqRYqQ"]
+    }
     """
 
 DID_DOC_NUMALGO_O_MULTIBASE = """
-       {
-           "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-           "authentication": [
-               {
-                   "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "type": "Ed25519VerificationKey2020",
-                   "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-               }
-           ]
-       }
+    {
+        "@context": [
+            "https://www.w3.org/ns/did/v1",
+            "https://w3id.org/security/suites/ed25519-2020/v1"
+        ],
+        "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+        "verificationMethod": [
+            {
+                "id": "#6MkqRYqQ",
+                "type": "Ed25519VerificationKey2020",
+                "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+                "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+            }
+        ],
+        "authentication": ["#6MkqRYqQ"],
+        "assertionMethod": ["#6MkqRYqQ"],
+        "capabilityInvocation": ["#6MkqRYqQ"],
+        "capabilityDelegation": ["#6MkqRYqQ"]
+    }
     """
 
 DID_DOC_NUMALGO_O_JWK = """
-        {
-            "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-            "authentication": [
-                {
-                    "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                    "type": "JsonWebKey2020",
-                    "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                    "publicKeyJwk": {
-                        "kty": "OKP",
-                        "crv": "Ed25519",
-                        "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA"
-                    }
+    {
+        "@context": [
+            "https://www.w3.org/ns/did/v1",
+            "https://w3id.org/security/suites/jws-2020/v1"
+        ],
+        "id": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+        "verificationMethod": [
+            {
+                "id": "#6MkqRYqQ",
+                "type": "JsonWebKey2020",
+                "controller": "did:peer:0z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+                "publicKeyJwk": {
+                    "kty": "OKP",
+                    "crv": "Ed25519",
+                    "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA"
                 }
-            ]
-        }
+            }
+        ],
+        "authentication": ["#6MkqRYqQ"],
+        "assertionMethod": ["#6MkqRYqQ"],
+        "capabilityInvocation": ["#6MkqRYqQ"],
+        "capabilityDelegation": ["#6MkqRYqQ"]
+    }
     """
 
 PEER_DID_NUMALGO_2 = (
@@ -55,138 +76,145 @@
 )
 
 DID_DOC_NUMALGO_2_BASE58 = """
-        {
-           "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-           "authentication": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "type": "Ed25519VerificationKey2018",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyBase58": "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
-               },
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg",
-                   "type": "Ed25519VerificationKey2018",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
-               }
-           ],
-           "keyAgreement": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-                   "type": "X25519KeyAgreementKey2019",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyBase58": "JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr"
-               }
-           ],
-           "service": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#didcommmessaging-0",
-                   "type": "DIDCommMessaging",
-                   "serviceEndpoint": "https://example.com/endpoint",
-                   "routingKeys": [
-                       "did:example:somemediator#somekey"
-                   ],
-                   "accept": [
-                        "didcomm/v2", "didcomm/aip2;env=rfc587"
-                   ]
-               }
-           ]
-       }
+    {
+        "@context": ["https://www.w3.org/ns/did/v1"],
+        "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+        "verificationMethod": [
+            {
+                "id": "#6LSbysY2",
+                "type": "X25519KeyAgreementKey2019",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyBase58": "JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr"
+            },
+            {
+                "id": "#6MkqRYqQ",
+                "type": "Ed25519VerificationKey2018",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyBase58": "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7"
+            },
+            {
+                "id": "#6MkgoLTn",
+                "type": "Ed25519VerificationKey2018",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
+            }
+        ],
+        "authentication": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "assertionMethod": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "keyAgreement": ["#6LSbysY2"],
+        "capabilityInvocation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "capabilityDelegation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "service": [
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+                "routingKeys": ["did:example:somemediator#somekey"],
+                "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"]
+            }
+        ]
+    }
     """
 
 DID_DOC_NUMALGO_2_MULTIBASE = """
-        {
-           "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-           "authentication": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "type": "Ed25519VerificationKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-               },
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg",
-                   "type": "Ed25519VerificationKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyMultibase": "z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg"
-               }
-           ],
-           "keyAgreement": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-                   "type": "X25519KeyAgreementKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                   "publicKeyMultibase": "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
-               }
-           ],
-           "service": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#didcommmessaging-0",
-                   "type": "DIDCommMessaging",
-                   "serviceEndpoint": "https://example.com/endpoint",
-                   "routingKeys": [
-                       "did:example:somemediator#somekey"
-                   ],
-                   "accept": [
-                        "didcomm/v2", "didcomm/aip2;env=rfc587"
-                   ]
-               }
-           ]
-       }
+    {
+        "@context": [
+            "https://www.w3.org/ns/did/v1",
+            "https://w3id.org/security/suites/x25519-2020/v1",
+            "https://w3id.org/security/suites/ed25519-2020/v1"
+        ],
+        "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+        "verificationMethod": [
+            {
+                "id": "#6LSbysY2",
+                "type": "X25519KeyAgreementKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyMultibase": "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
+            },
+            {
+                "id": "#6MkqRYqQ",
+                "type": "Ed25519VerificationKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+            },
+            {
+                "id": "#6MkgoLTn",
+                "type": "Ed25519VerificationKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyMultibase": "z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg"
+            }
+        ],
+        "authentication": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "assertionMethod": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "keyAgreement": ["#6LSbysY2"],
+        "capabilityInvocation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "capabilityDelegation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "service": [
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+                "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+                "routingKeys": ["did:example:somemediator#somekey"]
+            }
+        ]
+    }
     """
 
 DID_DOC_NUMALGO_2_JWK = """
-        {
-           "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-           "authentication": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "type": "JsonWebKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                    "publicKeyJwk": {
-                         "kty": "OKP",
-                         "crv": "Ed25519",
-                         "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA"
-                     }
-               },
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg",
-                   "type": "JsonWebKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                    "publicKeyJwk": {
-                         "kty": "OKP",
-                         "crv": "Ed25519",
-                         "x": "Itv8B__b1-Jos3LCpUe8EdTFGTCa_Dza6_3848P3R70"
-                     }
-               }
-           ],
-           "keyAgreement": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-                   "type": "JsonWebKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
-                    "publicKeyJwk": {
-                         "kty": "OKP",
-                         "crv": "X25519",
-                         "x": "BIiFcQEn3dfvB2pjlhOQQour6jXy9d5s2FKEJNTOJik"
-                     }
-               }
-           ],
-           "service": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0#didcommmessaging-0",
-                   "type": "DIDCommMessaging",
-                   "serviceEndpoint": "https://example.com/endpoint",
-                   "routingKeys": [
-                       "did:example:somemediator#somekey"
-                   ],
-                   "accept": [
-                        "didcomm/v2", "didcomm/aip2;env=rfc587"
-                   ]
-               }
-           ]
-       }
+    {
+        "@context": [
+            "https://www.w3.org/ns/did/v1",
+            "https://w3id.org/security/suites/jws-2020/v1"
+        ],
+        "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+        "verificationMethod": [
+            {
+                "id": "#6LSbysY2",
+                "type": "JsonWebKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyJwk": {
+                    "kty": "OKP",
+                    "crv": "X25519",
+                    "x": "BIiFcQEn3dfvB2pjlhOQQour6jXy9d5s2FKEJNTOJik"
+                }
+            },
+            {
+                "id": "#6MkqRYqQ",
+                "type": "JsonWebKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyJwk": {
+                    "kty": "OKP",
+                    "crv": "Ed25519",
+                    "x": "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA"
+                }
+            },
+            {
+                "id": "#6MkgoLTn",
+                "type": "JsonWebKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0",
+                "publicKeyJwk": {
+                    "kty": "OKP",
+                    "crv": "Ed25519",
+                    "x": "Itv8B__b1-Jos3LCpUe8EdTFGTCa_Dza6_3848P3R70"
+                }
+            }
+        ],
+        "authentication": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "assertionMethod": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "keyAgreement": ["#6LSbysY2"],
+        "capabilityInvocation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "capabilityDelegation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "service": [
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+                "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+                "routingKeys": ["did:example:somemediator#somekey"]
+            }
+        ]
+    }
     """
 
 PEER_DID_NUMALGO_2_2_SERVICES = (
@@ -197,44 +225,48 @@
 )
 
 DID_DOC_NUMALGO_2_MULTIBASE_2_SERVICES = """
-        {
-            "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0",
-            "authentication": [
-                {
-                    "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                    "type": "Ed25519VerificationKey2020",
-                    "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0",
-                    "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                }
-            ],
-            "keyAgreement": [
-                {
-                    "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0#6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud",
-                    "type": "X25519KeyAgreementKey2020",
-                    "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0",
-                    "publicKeyMultibase": "z6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud"
-                }
-            ],
-            "service": [
-                {
-                    "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0#didcommmessaging-0",
-                    "type": "DIDCommMessaging",
-                    "serviceEndpoint": "https://example.com/endpoint",
-                    "routingKeys": [
-                        "did:example:somemediator#somekey"
-                    ]
-                },
-                {
-                    "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0#example-1",
-                    "type": "example",
-                    "serviceEndpoint": "https://example.com/endpoint2",
-                    "routingKeys": [
-                        "did:example:somemediator#somekey2"
-                    ],
-                    "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"]
-                }
-            ]
-        }
+    {
+        "@context": [
+            "https://www.w3.org/ns/did/v1",
+            "https://w3id.org/security/suites/x25519-2020/v1",
+            "https://w3id.org/security/suites/ed25519-2020/v1"
+        ],
+        "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0",
+        "verificationMethod": [
+            {
+                "id": "#6LSpSrLx",
+                "type": "X25519KeyAgreementKey2020",
+                "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0",
+                "publicKeyMultibase": "z6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud"
+            },
+            {
+                "id": "#6MkqRYqQ",
+                "type": "Ed25519VerificationKey2020",
+                "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.SW3sidCI6ImRtIiwicyI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il19LHsidCI6ImV4YW1wbGUiLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludDIiLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5MiJdLCJhIjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfV0",
+                "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+            }
+        ],
+        "authentication": ["#6MkqRYqQ"],
+        "assertionMethod": ["#6MkqRYqQ"],
+        "keyAgreement": ["#6LSpSrLx"],
+        "capabilityInvocation": ["#6MkqRYqQ"],
+        "capabilityDelegation": ["#6MkqRYqQ"],
+        "service": [
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint",
+                "routingKeys": ["did:example:somemediator#somekey"]
+            },
+            {
+                "id": "#example-1",
+                "type": "example",
+                "serviceEndpoint": "https://example.com/endpoint2",
+                "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"],
+                "routingKeys": ["did:example:somemediator#somekey2"]
+            }
+        ]
+    }
     """
 
 PEER_DID_NUMALGO_2_NO_SERVICES = (
@@ -244,60 +276,76 @@
 )
 
 DID_DOC_NUMALGO_2_MULTIBASE_NO_SERVICES = """
-        {
-            "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-            "authentication": [
-                {
-                    "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                    "type": "Ed25519VerificationKey2020",
-                    "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                    "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-                }
-            ],
-            "keyAgreement": [
-                {
-                    "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V#6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud",
-                    "type": "X25519KeyAgreementKey2020",
-                    "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                    "publicKeyMultibase": "z6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud"
-                }
-            ]
-        }
+    {
+        "@context": [
+            "https://www.w3.org/ns/did/v1",
+            "https://w3id.org/security/suites/x25519-2020/v1",
+            "https://w3id.org/security/suites/ed25519-2020/v1"
+        ],
+        "id": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+        "verificationMethod": [
+            {
+                "id": "#6LSpSrLx",
+                "type": "X25519KeyAgreementKey2020",
+                "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+                "publicKeyMultibase": "z6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud"
+            },
+            {
+                "id": "#6MkqRYqQ",
+                "type": "Ed25519VerificationKey2020",
+                "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
+                "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+            }
+        ],
+        "authentication": ["#6MkqRYqQ"],
+        "assertionMethod": ["#6MkqRYqQ"],
+        "keyAgreement": ["#6LSpSrLx"],
+        "capabilityInvocation": ["#6MkqRYqQ"],
+        "capabilityDelegation": ["#6MkqRYqQ"]
+    }
     """
 
 PEER_DID_NUMALGO_2_MINIMAL_SERVICES = "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9"
 
 DID_DOC_NUMALGO_2_MULTIBASE_MINIMAL_SERVICES = """
-        {
-           "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
-           "authentication": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9#6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V",
-                   "type": "Ed25519VerificationKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
-                   "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
-               },
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9#6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg",
-                   "type": "Ed25519VerificationKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
-                   "publicKeyMultibase": "z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg"
-               }
-           ],
-           "keyAgreement": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9#6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc",
-                   "type": "X25519KeyAgreementKey2020",
-                   "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
-                   "publicKeyMultibase": "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
-               }
-           ],
-           "service": [
-               {
-                   "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9#didcommmessaging-0",
-                   "serviceEndpoint": "https://example.com/endpoint",
-                   "type": "DIDCommMessaging"
-               }
-           ]
-       }
+    {
+        "@context": [
+            "https://www.w3.org/ns/did/v1",
+            "https://w3id.org/security/suites/x25519-2020/v1",
+            "https://w3id.org/security/suites/ed25519-2020/v1"
+        ],
+        "id": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
+        "verificationMethod": [
+            {
+                "id": "#6LSbysY2",
+                "type": "X25519KeyAgreementKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
+                "publicKeyMultibase": "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc"
+            },
+            {
+                "id": "#6MkqRYqQ",
+                "type": "Ed25519VerificationKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
+                "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V"
+            },
+            {
+                "id": "#6MkgoLTn",
+                "type": "Ed25519VerificationKey2020",
+                "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9",
+                "publicKeyMultibase": "z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg"
+            }
+        ],
+        "authentication": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "assertionMethod": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "keyAgreement": ["#6LSbysY2"],
+        "capabilityInvocation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "capabilityDelegation": ["#6MkqRYqQ", "#6MkgoLTn"],
+        "service": [
+            {
+                "id": "#didcommmessaging-0",
+                "type": "DIDCommMessaging",
+                "serviceEndpoint": "https://example.com/endpoint"
+            }
+        ]
+    }
     """