Skip to main content

An implementation of did:peer:2

Project description

did-peer-2

pypi release

A minimal did:peer:2 (and 3) library.

did:peer:2 has (or will soon be) superseded by did:peer:4. Even so, we anticipate did:peer:2 being around for at least a while longer. This library is built against the most recent version of the did:peer:2 spec.

Install

pip install did-peer-2

Usage

>>> from did_peer_2 import generate, KeySpec, resolve, peer2to3
>>> # Define keys using KeySpec
>>> keys = [
...     KeySpec.verification("z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc"),
...     KeySpec.encryption("z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR")
... ]
>>> # Define service objects
>>> services = [
...     {
...         "type": "DIDCommMessaging",
...         "serviceEndpoint": {
...             "uri": "http://example.com/didcomm",
...             "accept": ["didcomm/v2"],
...             "routingKeys": ["did:example:123456789abcdefghi#key-1"],
...         },
...     },
... ]
>>>
>>> # Generate the DID
>>> did = generate(keys, services)
>>> print(did)
did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ
>>>
>>> # Resolve the DID
>>> resolved = resolve(did)
>>> # The resolved document will be a dictionary
>>> assert isinstance(resolved, dict)
>>>
>>> # Let's print it out
>>> import json
>>> print(json.dumps(resolved, indent=2))
{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/multikey/v1"
  ],
  "id": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ",
  "verificationMethod": [
    {
      "type": "Multikey",
      "id": "#key-1",
      "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ",
      "publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc"
    },
    {
      "type": "Multikey",
      "id": "#key-2",
      "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ",
      "publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR"
    }
  ],
  "authentication": [
    "#key-1"
  ],
  "keyAgreement": [
    "#key-2"
  ],
  "service": [
    {
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "http://example.com/didcomm",
        "accept": [
          "didcomm/v2"
        ],
        "routingKeys": [
          "did:example:123456789abcdefghi#key-1"
        ]
      },
      "id": "#service"
    }
  ],
  "alsoKnownAs": [
    "did:peer:3zQmbRvRJgKBuubq8T9VBjrDPTmjb2Ed91f89ekW4gr6aZxa"
  ]
}
>>> # Let's derive the did:peer:3
>>> did3 = peer2to3(did)
>>> print(did3)
did:peer:3zQmbRvRJgKBuubq8T9VBjrDPTmjb2Ed91f89ekW4gr6aZxa

DID Peer 2 Specification

If numalgo == 2, the generation mode is similar to Method 0 (and therefore also did:key) with the ability to specify additional keys in the generated DID Document. This method is necessary when both an encryption key and a signing key are required. This method also enables including services in the generated DID Document.

[!NOTE] The first iteration of this method left some elements of the encoding and decoding process underspecified. Clarifications have been made to this specification to resolve this. These clarifications will be noted by appending "(clarified)" to the relevant statements.

peer-did-method-2 = "did:peer:2" 1*element 
element = "." ( purposecode transform encnumbasis / service )
purposecode = "A" / "E" / "V" / "I" / "D" / "S" 
keypurpose = 
transform = "z"
encnumbasis = 46*BASE58BTC
service = 1*B64URL

Generating a did:peer:2

When generating a did:peer:2, take as inputs a set of keys and their purpose. Each key's purpose corresponds to the Verification Relationship it will hold in the DID Document generated from the DID.

Abstractly, these inputs may look like the following (in this example, the keys are already multibase, multicodec encoded values):

[
  {
    "purpose": "verification",
    "publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc"
  },
  {
    "purpose": "encryption",
    "publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR"
  }
]

To encode these keys:

  • Construct a multibase, multicodec form of each public key to be included.
  • Prefix each encoded key with a period character (.) and single character from the purpose codes table below.
  • Concatenate the prefixed encoded keys. The inputs above will result in:
    .Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR
    

In addition to keys, did:peer:2 can encode one or more services.

The service SHOULD follow the DID Core specification for services.

For use with did:peer:2, service id attributes MUST be relative. The service MAY omit the id; however, this is NOT recommended (clarified).

Consider the following service as input:

{
  "type": "DIDCommMessaging",
  "serviceEndpoint": {
    "uri": "http://example.com/didcomm",
    "accept": [
      "didcomm/v2"
    ],
    "routingKeys": [
      "did:example:123456789abcdefghi#key-1"
    ]
  }
}

To encode a service:

  • Start with the JSON structure for your service, like the example input above.
  • Recursively replace common strings in key names and type value with abbreviations from the abbreviations table below (clarified). For the above input, this will result in:
    {
      "t": "dm",
      "s": {
        "uri": "http://example.com/didcomm",
        "a": [
          "didcomm/v2"
        ],
        "r": [
          "did:example:123456789abcdefghi#key-1"
        ]
      }
    }
    
  • Convert to string, and remove unnecessary whitespace, such as spaces and newlines. For the above input, this will result in:
    {"t":"dm","s":{"uri":"http://example.com/didcomm","a":["didcomm/v2"],"r":["did:example:123456789abcdefghi#key-1"]}}
    
  • Base64URL Encode String (Padding MUST be removed as the "=" character is, per the DID Core Specification, not permitted in a DID). For the above example, this will result in:
    eyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ
    
  • Prefix encoded service with a period character (.) and S. For the above input, this will result in:
    .SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYWNjZXB0IjpbImRpZGNvbW0vdjIiXSwicm91dGluZ0tleXMiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ
    
  • For any additional services, repeat the steps above and concatenate each additional service to the previous (clarified). This will result in a string like the following (newline added between service strings for clarity; in practice, there will be no whitespace between the concatenated services):
    .SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYWNjZXB0IjpbImRpZGNvbW0vdjIiXSwicm91dGluZ0tleXMiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ
    .SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ
    

Finally, to create the DID, concatenate the following values:

  • did:peer:2
  • Encoded, concatenated, and prefixed keys.
  • Encoded, concatenated, and prefixed services.

This concatenation will result in a value like the following:

did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ

Lookup Tables

Common String Abbreviations

Common String Abbreviation
type t
DIDCommMessaging dm
serviceEndpoint s
routingKeys r
accept a

Purpose Codes

Purpose Code Verification Relationship
A Assertion
E Key Agreement (Encryption)
V Authentication (Verification)
I Capability Invocation
D Capability Delegation
S Service

Resolving a did:peer:2

[!NOTE] Below is the normative approach to resolving did:peer:2 DIDs. However, it is often the case that the resolved value is only used within a particular component. In this case, some of these rules may be relaxed. For instance, the verification material may be transformed into a JWK or other representation if the resolving component is more accustomed to working with those key representations. It is not strictly necessary to first represent the document as described here only to immediately transform it into the more familiar representation. Shortcuts like these are not problematic unless they impact the function of the DID Document.

The id value of the Document, verification method, and service objects MUST be set as outlined below. These values are used to reference elements of the document and must be consistent across implementations regardless of shortcuts taken within the resolver.

When Resolving the peer DID into a DID Document, the process is reversed:

  • Start with an empty document with the DID Core context and Multikey context (clarified):
    {
        "@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/multikey/v1"]
    }
    
  • Set the id of the document to the DID being resolved.
  • Optionally, set the alsoKnownAs to the did:peer:3 value corresponding to the DID being resolved.
  • Split the DID string into elements.
  • For each element with a purpose corresponding to a key, transform keys into verification methods in the DID Document:
    • Remove the period (.) and the Purpose prefix. Consider the remaining string the "encoded key."
    • Create an empty object. Consider this value the "verification method."
    • Set the type of the verification method to Multikey (clarified).
    • Set the id of the verification method to #key-N where N is an incrementing number starting at 1 (clarified). The keys MUST be processed in the order they appear in the DID string. For example, if you have the DID (whitespace added for example only):
      did:peer:2
          .Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc
          .Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR
          .SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ
          .SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ
      
      The key with purpose code V and encoded key value z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc will have the id: #key-1. The key with purpose code E and encoded key value z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR will have the id: #key-2.
    • Set the controller of the verification method to the value of the DID being resolved.
    • Set the publicKeyMultibase of the verification method to the value of the encoded key.
    • Append this object to verificationMethod of the document (clarified).
    • Append a reference to the verification method to the appropriate verification relationship, using the lookup table above. The reference should be the exact value used in the id of the verification method (clarified). For example, using the DID above and the key with purpose code V:
      {
        ... // Context and other elements previously added to the document
        "authentication": [..., "#key-1"]
      }
      
  • For each element with a purpose corresponding to a service, transform the service and add to the DID Document:
    • Remove the period (.) and S prefix.
    • Base64URL Decode String.
    • Parse as JSON.
    • Replace abbreviations in key names and type value with common names from the abbreviations table above.
    • If the id is NOT set (clarified):
      • Set id to #service for the first such service.
      • For all subsequent services WITHOUT an id, set id to #service-1, #service-2, etc. incrementing the integer with each service, starting from 1.

[!NOTE] It is not possible to express a verification method not controlled by the controller of the DID Document with did:peer:2.

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/multikey/v1",
  ],
  "id": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
  "verificationMethod": [
  {
    "id": "#key-1",
    "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
    "type": "Multikey",
    "publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc",
  },
  {
    "id": "#key-2",
    "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
    "type": "Multikey",
    "publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR",
  },
  ],
  "authentication": ["#key-1"],
  "keyAgreement": ["#key-2"],
  "service": [
    {
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "http://example.com/didcomm",
        "accept": ["didcomm/v2"],
        "routingKeys": ["did:example:123456789abcdefghi#key-1"],
      },
      "id": "#service",
    },
    {
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "http://example.com/another",
        "accept": ["didcomm/v2"],
        "routingKeys": ["did:example:123456789abcdefghi#key-2"],
      },
      "id": "#service-1",
    },
  ],
  "alsoKnownAs": ["did:peer:3zQmd6RdU6e2nDrLn1rjwdA5Buzq7wJwsv3WJ1AgrwKYJoLE"],
}

DID Peer 3: DID Shortening with SHA-256 Hash

If numalgo == 3, the generation mode is similar to Method 2, but with a shorter DID identifier derived from a SHA-256 hash of the original identifier. The benefit of using Method 3 over Method 2 is the ability to have smaller size didcomm messages as did:peer:2. dids tend to be verbose in nature. Method 3 peer dids can only be used after a peer did method 2 has been exchange with the other party and thus can map the shortened did to the longform one. In order to send a message encrypted with method 3 you first MUST send a discover-feature message (using the method 2 as the to field) to make sure that the receiving agent is capable of resolving method 3 dids.

peer-did-method-3 = "did:peer:3" transform encnumbasis
transform = "z"
encnumbasis = 46*BASE58BTC
  • Start with the DID generated using Method 2.
  • Take the SHA-256 hash of the generated DID (excluding the "did:peer:2" prefix).
  • Encode the hash using the base58btc multibase encoding.
  • Construct the final Method 3 DID by concatenating the prefix "did:peer:3" with the encoded hash.

For example, if the Method 2 DID is:

did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0

First, remove the prefix "did:peer:2":

.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0

Take the SHA-256 hash of the remaining string and represent as a multi-hash, multi-base encoded(base58btc) string:

zQmS19jtYDvGtKVrJhQnRFpBQAx3pJ9omx2HpNrcXFuRCz9

Finally, concatenate the prefix "did:peer:3" with the computed and encoded hash:

did:peer:3zQmS19jtYDvGtKVrJhQnRFpBQAx3pJ9omx2HpNrcXFuRCz9

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

did_peer_2-0.1.2.tar.gz (12.7 kB view hashes)

Uploaded Source

Built Distribution

did_peer_2-0.1.2-py3-none-any.whl (8.8 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page