Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use multikey #1

Merged
merged 1 commit into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 38 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,18 @@ did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrG
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2020/v1",
"https://w3id.org/security/suites/x25519-2020/v1"
"https://w3id.org/security/multikey/v1"
],
"id": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ",
"verificationMethod": [
{
"type": "Ed25519VerificationKey2020",
"type": "Multikey",
"id": "#key-1",
"controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ",
"publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc"
},
{
"type": "X25519KeyAgreementKey2020",
"type": "Multikey",
"id": "#key-2",
"controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ",
"publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR"
Expand All @@ -87,6 +86,9 @@ did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrG
},
"id": "#service"
}
],
"alsoKnownAs": [
"did:peer:3zQmbRvRJgKBuubq8T9VBjrDPTmjb2Ed91f89ekW4gr6aZxa"
]
}
>>> # Let's derive the did:peer:3
Expand Down Expand Up @@ -117,7 +119,7 @@ service = 1*B64URL

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](https://www.w3.org/TR/did-core/#verification-relationships) it will hold in the DID Document generated from the DID.

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

```json
[
Expand All @@ -134,7 +136,7 @@ Abstractly, these inputs may look like the following:

To encode these keys:

* Construct a multibase, multicodec form of each public key to be included.
* Construct a [multibase](https://github.com/multiformats/multibase), [multicodec](https://github.com/multiformats/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:
```
Expand Down Expand Up @@ -236,13 +238,6 @@ did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrG
| **S** | Service |


#### Multicodec Prefix Name to Verification Method Type (clarified)

| Multicodec Prefix Name | Verification Method Type |
|------------------------------------|----------------------------|
| ed25519-pub | Ed25519VerificationKey2020 |
| x25519-pub | X25519KeyAgreementKey2020 |

### Resolving a `did:peer:2`

> [!NOTE]
Expand All @@ -252,27 +247,19 @@ did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrG

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

* Start with an empty document with the DID Core context (clarified):
* Start with an empty document with the DID Core context and [Multikey context](https://www.w3.org/TR/vc-data-integrity/#multikey) (clarified):
```json
{
"context": ["https://www.w3.org/ns/did/v1"]
"@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/multikey/v1"]
}
```
* If any of the keys in the DID are ed25519, add the following context:
```
https://w3id.org/security/suites/ed25519-2020/v1
```
* If any of the keys in the DID are x25519, add the following context:
```
https://w3id.org/security/suites/x25519-2020/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 according to the multicodec prefix using the lookup table above (clarified).
* Set the `type` of the verification method to [`Multikey`](https://www.w3.org/TR/vc-data-integrity/#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
Expand Down Expand Up @@ -308,56 +295,48 @@ When Resolving the peer DID into a DID Document, the process is reversed:

```json
{
"@context": "https://www.w3.org/ns/did/v1",
"@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": "Ed25519VerificationKey2020",
"publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc"
},
{
"id": "#key-2",
"controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
"type": "X25519KeyAgreementKey2020",
"publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR"
}
],
"authentication": [
"#key-1"
],
"keyAgreement": [
"#key-2"
{
"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"
]
"accept": ["didcomm/v2"],
"routingKeys": ["did:example:123456789abcdefghi#key-1"],
},
"id": "#service"
"id": "#service",
},
{
"type": "DIDCommMessaging",
"serviceEndpoint": {
"uri": "http://example.com/another",
"accept": [
"didcomm/v2"
],
"routingKeys": [
"did:example:123456789abcdefghi#key-2"
]
"accept": ["didcomm/v2"],
"routingKeys": ["did:example:123456789abcdefghi#key-2"],
},
"id": "#service-1"
}
]
"id": "#service-1",
},
],
"alsoKnownAs": ["did:peer:3zQmd6RdU6e2nDrLn1rjwdA5Buzq7wJwsv3WJ1AgrwKYJoLE"],
}
```

Expand Down
35 changes: 9 additions & 26 deletions did_peer_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,15 @@ def decode_service(self, data: str) -> Dict[str, Any]:
)


MultibaseEncodedKey = str
MultikeyEncodedKey = str


@dataclass
class KeySpec:
"""Key specification for did:peer:2."""

purpose: PurposeCode
material: MultibaseEncodedKey
material: MultikeyEncodedKey

@classmethod
def assertion(cls, material: str) -> "KeySpec":
Expand Down Expand Up @@ -185,24 +185,6 @@ def capability_delegation(cls, material: str) -> "KeySpec":
"""Create a key spec for capability delegation purposes."""
return cls(PurposeCode.capability_delegation, material)

@property
def vm_type(self) -> str:
"""Determine the vm type from the multibase encoded key."""
if self.material.startswith("z6Mk"):
return "Ed25519VerificationKey2020"
if self.material.startswith("z6LS"):
return "X25519KeyAgreementKey2020"
raise ValueError(f"Unsupported key type: {self.material}")

@property
def required_contexts(self) -> List[str]:
"""Determine the required context from the multibase encoded key."""
if self.material.startswith("z6Mk"):
return ["https://w3id.org/security/suites/ed25519-2020/v1"]
if self.material.startswith("z6LS"):
return ["https://w3id.org/security/suites/x25519-2020/v1"]
raise ValueError(f"Unsupported key type: {self.material}")


def generate(keys: Sequence[KeySpec], services: Sequence[Dict[str, Any]]):
"""Generate a did:peer:2 DID from keys and services.
Expand All @@ -228,7 +210,10 @@ def resolve(did: str) -> Dict[str, Any]:
raise ValueError(f"Invalid did:peer:2: {did}")

document = {}
document["@context"] = ["https://www.w3.org/ns/did/v1"]
document["@context"] = [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1",
]
document["id"] = did

elements = did.split(".")[1:]
Expand All @@ -243,10 +228,9 @@ def resolve(did: str) -> Dict[str, Any]:
assert purpose == PurposeCode.service
services.append(service_encoder.decode_service(element[1:]))

additional_contexts = set()
for index, key in enumerate(keys, start=1):
verification_method = {
"type": key.vm_type,
"type": "Multikey",
"id": f"#key-{index}",
"controller": did,
"publicKeyMultibase": key.material,
Expand All @@ -255,9 +239,6 @@ def resolve(did: str) -> Dict[str, Any]:
document.setdefault(key.purpose.verification_relationship, []).append(
f"#key-{index}"
)
additional_contexts.update(key.required_contexts)

document["@context"].extend(sorted(additional_contexts))

unidentified_index = 0
for service in services:
Expand All @@ -269,6 +250,8 @@ def resolve(did: str) -> Dict[str, Any]:
unidentified_index += 1
document.setdefault("service", []).append(service)

document["alsoKnownAs"] = [peer2to3(did)]

return document


Expand Down
8 changes: 4 additions & 4 deletions tests/test_did_peer_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,20 @@ def test_generate_resolve():
assert resolved == {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2020/v1",
"https://w3id.org/security/suites/x25519-2020/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": "Ed25519VerificationKey2020",
"type": "Multikey",
"publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc",
},
{
"id": "#key-2",
"controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
"type": "X25519KeyAgreementKey2020",
"type": "Multikey",
"publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR",
},
],
Expand All @@ -77,6 +76,7 @@ def test_generate_resolve():
"id": "#service-1",
},
],
"alsoKnownAs": ["did:peer:3zQmd6RdU6e2nDrLn1rjwdA5Buzq7wJwsv3WJ1AgrwKYJoLE"],
}


Expand Down