From 7fad25b30e4f8d0c36e1b21de1ba26fa3b10ef2a Mon Sep 17 00:00:00 2001 From: Joel Thorstensson Date: Fri, 13 Jan 2023 14:22:24 +0000 Subject: [PATCH 1/6] Rewrite of 3ID --- CIPs/CIP-79/CIP-79.md | 525 ++++++++++++++++++++++++++++-------------- 1 file changed, 348 insertions(+), 177 deletions(-) diff --git a/CIPs/CIP-79/CIP-79.md b/CIPs/CIP-79/CIP-79.md index de3e7b5..7bbb021 100644 --- a/CIPs/CIP-79/CIP-79.md +++ b/CIPs/CIP-79/CIP-79.md @@ -1,281 +1,452 @@ --- cip: 79 -title: 3ID DID Method Specification +title: 3 DID Method Specification author: Joel Thorstensson (@oed) discussions-to: https://github.com/ceramicnetwork/CIP/issues/80 status: Draft category: Standards -type: RFC +type: Core created: 2021-02-12 +updated: 2023-01-13 --- -# 3ID DID Method Specification +## Simple Summary -3ID is a DID method that is implemented natively on Ceramic. It uses the Tile Document StreamType to create a mutable stream that stores the information which makes up the DID document for the 3ID. The Tile Document StreamType supports secure key rotation for 3IDs since its updates must be anchored into a blockchain, providing explicit versions and *proof-of-publication* at specific points in time (blockheights). This means that 3ID inherits this property. + +The 3 DID method enables users to compose multiple accounts into a signle identifier. -## DID Method Name -The name string that shall identify this DID method is: `3`. +## Abstract -A DID that uses this method MUST begin with the following prefix: `did:3`. Per the [DID specification](https://w3c.github.io/did-core/), this string MUST be in lowercase. The remainder of the DID, after the prefix, is specified below. + +With a special type of Ceramic stream 3ID enables a revocation registry that can be used to add and remove verification methods from the 3 DID method as well as revoke any capability issued by the identifier. The revocation registry is based on hashes of object-capabilities encoded as CACAO. -## Method Specific Identifier -There are two versions of 3IDs. Both versions use a Ceramic Tile Document StreamType as a way to update the DID document. 3IDv1 is the most recent version, however 3IDv0 is supported for legacy reasons. If you are creating new 3IDs you should always use 3IDv1. Both versions are always encoded using multibase. To determine if it's v1 or v0, first convert the multibase string into a byte array. If the first varint is `0x01` it's a 3IDv0, and if the first varint is `0xce` it's a 3IDv1. +## Motivation -### 3IDv1 + +Currently in Ceramic the main accounts types are PKH DID. These are great because they enable existing wallets to be used directly with Ceramic. However, these accounts are inherently tied to a specific account and there is no way to rotate keys in a simple manner. The 3 DID method changes this by defining a DID method which works with object-capabilities and supports all DID CRUD operations. -The method specific identifier for 3IDv1 is simply a Ceramic StreamID. The StreamID used refers to the Ceramic stream which contains the information needed to construct the DID Document upon resolution. StreamIDs are encoded according to [CIP-59](https://github.com/ceramicnetwork/CIP/blob/master/CIPs/CIP-59/CIP-59.md). +Furthermore, the revocation regsitry of the 3 DID method enables the DID subject to revoke any object-capability issued by the 3ID. This can be useful in case of a key compromise, e.g. for a temporary session key. -``` -3idv1 = "did:3:" -``` +## Specification -#### Example + +Specification goes here. -```sh -did:3:kjzl6cwe1jw149tlplc4bgnpn1v4uwk9rg9jkvijx0u0zmfa97t69dnqibqa2as -``` +### The did:3 identifier -### 3IDv0 +> ``` +> did:3: +> ``` -The method specific identifier for 3IDv0 is a [CID](https://github.com/multiformats/cid) as produced by the [IPLD](https://github.com/ipld/specs) codec [dag-cbor](https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-cbor.md). +The `` value is a `keccak-256` multihash over the CID of a CACAO object-capability, e.g. ReCap or UCAN. The value MUST be encoded as a multibase string, using `base58btc`. -``` -3idv0 = "did:3:" -``` +***Simple example:*** + +> ``` +> did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj +> ``` -#### Example +### CRUD Operation Definitions -```sh -did:3:bafyreiffkeeq4wq2htejqla2is5ognligi4lvjhwrpqpl2kazjdoecmugi +3IDs are created, updated, and deactivated by creating, notarizing, and revoking object-capabilities in the form of CACAOs. + +#### Create + +Create and sign a [SIWx](https://chainagnostic.org/CAIPs/caip-122) message where: + +- `address` - a blockchain address (e.g. `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) +- `uri` - the PKH DID for the same address (e.g. `did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) + +And resources contains the following ReCap object: + +```java +{ + "att": { + "did:3:new": { "3id/control": [] } + } +} +``` + +- *When signing this would look something like this for the user:* + + ``` + example.com wants you to sign in with your Ethereum account: + 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + + I further authorize https://example.com to perform the following + actions on my behalf: (1) "3id/control" for "did:3:new". + + URI: did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + Version: 1 + Chain ID: 1 + Nonce: n-0S6_WzA2Mj + Issued At: 2022-06-21T12:00:00.000Z + Resources: + - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 + ``` + +##### Create the DID + +```jsx +cacaoCID = ipld.put(CACAO(SIWx-message, signature)) +did = 'did:3:' + multihash(cacaoCID) ``` -## CRUD Operation Definitions +#### Read -In this section the CRUD operations for a 3ID DID are defined. +To read you must load a deterministic Ceramic stream to find any updates made to the 3ID. -### Create +1. Load the revocation registry Ceramic stream -A `3` DID is created by simply creating a stream that conforms to the [`tile document`](https://github.com/ceramicnetwork/CIP/blob/master/CIPs/CIP-8/CIP-8.md) StreamType. The [`tile document`](https://github.com/ceramicnetwork/CIP/blob/master/CIPs/CIP-8/CIP-8.md) takes a DID as the *controller*, and it's recommended that a `did:key` is used. The *controller* is the DID which is allowed to update the stream. The *family* of the stream is set to `3id`, and the *deterministic* flag is set to `true`. + 1. If the `?versionTime=` is specified load only the events `≤ timestamp` -Now the content of the stream should consist of a JSON object with one property *publicKeys*. These public keys will be allowed to sign messages on behalf of the 3ID, or decrypt messages encrypted to the 3ID. The value of this property should be an object where the value is a [multicodec](https://github.com/multiformats/multicodec/) + multibase(*base58btc*) encoded public key, the key for any given key should be the last *15* characters of the encoded public key. +2. Read all entries where `isRevoked = false` -The 3ID DID method supports any type of public key that can be encoded using multicodec which can easily be extended to support quantum resistant signature and encryption schemes in the future. +3. For every CACAO multihash in the registry, as well as the 3ID identifier, -#### Example + 1. Add the following object to the `verificationMethod` property of the DID document, + + ```json + { + "id": "#", + "type": "capabilityHash", + "controller": "did:3:", + "multihash": "" + } + ``` + + 2. Add `"#"` to the following fields, + + 1. `authentication` + 2. `assertionMethod` + 3. `capabilityDelegation` + 4. `capabilityInvocation` -Below you can see an example of how to create a 3ID using the Ceramic javascript api. +##### Example DID Document -```js -const doc = await ceramic.createDocument({ - metadata: { - controllers: ['did:key:zQ3shQNcackrTByiYaPGso1Nt7b6r1gSMg4XXBmavzvTMqX1h'], // secp256k1 did:key - family: '3id' - }, - content: { - publicKeys: { - "XQCT2xJHsdY6iJH": "z6LSqKWh3XQ7AfsJuE2KR23cozEut8D5CXQCT2xJHsdY6iJH", // x22519 public key - "yh27jTt7Ny2Pwdy": "zQ3shrMGEKAjUTMmvDkcZ7Y3x9XnVjTH3myh27jTt7Ny2Pwdy", // secp256k1 public key - } - }, - deterministic: true -}) +For `did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj` with no entires in the Revocation registry, -const didString = `did:3:${doc.id}` +```json +{ + "@context": [ + "", + ] + "id": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "verificationMethod": [{ + "id": "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "type": "capabilityHash", + "controller": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "multihash": "z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" + }], + "authentication": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], + "assertionMethod": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], + "capabilityDelegation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], + "capabilityInvocation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], +} ``` -### Read/Verify +#### Update -Resolving a 3ID is quite straight forward. It is done by taking the StreamID from the method specific identifier, looking up the referred stream using Ceramic, and converting the content of the stream into a DID document. +##### To add a verification method: -#### Loading 3IDv1 stream +1. Create a new ReCap capability with an existing VM as the issuer, delegating `"3id/control"` to another DID (PKH or Key DID), and encode it as a CACAO. -To load a 3IDv1 document simply take the StreamID from the method specific identifier and load the stream from ceramic. + ***ReCap*** -#### Loading 3IDv0 document + ```json + { + "att": { + "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { "3id/control": [] } + } + } + ``` -To load a 3IDv0 document, first take the CID from the method specific identifier and load the corresponding object from the IPFS network. The resolved object will contain a `publicKey` property which has an array of public key objects (see [Appendix A](#appendix-a)). + - *When signing this would look something like this for the user:* -Now find the key with an id that ends in `#signingKey` and convert it to a multicodec encoded key (in compressed format), then use it as a `did:key` and look up the ceramic document which has this key as the *controller* and *family* set to `3id`, using the *deterministic* flag. Below you can see the code to do this with the javascript Ceramic api. + ``` + example.com wants you to sign in with your Ethereum account: + 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + + I further authorize https://example.com to perform the following + actions on my behalf: (1) "3id/control" for "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj". + + URI: did:pkh:eip155:1:0xa05bba39b223fe8d0a0e5c4f27ead9083cb22ee3 + Version: 1 + Chain ID: 1 + Nonce: n-0S6_WzA2Mj + Issued At: 2022-06-21T12:00:00.000Z + Resources: + - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 + ``` +2. Load the *Revocation Registry* stream +3. Update (2) by adding the `cacao-mh` from (1) -```js -const doc = await ceramic.createDocument({ - metadata: { - controllers: [didKey], // secp256k1 did:key - family: '3id' - }, - deterministic: true -}) -``` +***To remove a verification method:*** -#### Converting the loaded Ceramic stream to the DID document +1. Load the *Revocation Registry* stream +2. Update (1) by removing the `cacao-mh` that is being revoked -Once we have the stream loaded, load the latest *AnchorCommit* in the stream (the latest commit that was anchored to a blockchain). Then get the content of the stream at this `AnchorCommit`, which will look something like this: +#### Deactivate -```json -{ - "publicKeys": { - "j9uh8iKHSDSLat4": "zQ3shaLgXkpEXt7He5mogBxFfib5cE2kv9j9uh8iKHSDSLat4", - "qYfZN2QNDgjJpaL": "z6LSnTyV1nSWfMmfV1PoRmo3enhDnfqfFqYfZN2QNDgjJpaL" - } +In order to deactivate a 3ID all capabilities will need to be revoked. + +### Revocation Registry + +3ID is based on a self-certifying revocation registry represented as a special type of Ceramic stream. In it any verification method belonging to the 3ID can be registered and revoked. Every update to the registry is recorded as a *Data Event*. When a new event is created is needs to include a valid delegation chain back to previous version of the registry. + +```verilog +type Prinicipal Bytes // multidid +type CACAOHash Bytes // multihash +type Varsig Bytes // varsig + +type RevocationEntry struct { + key CACAOHash + isRevoked Boolean +} representation tuple +// The registry should eventually be a HAMT or similar data structure +type Regsitry { CACAOHash : RevocationEntry } +type Snapshot struct { + registry &Regsitry + actions [RevocationEntry] } ``` -To convert this into a DID document first create an empty DID document: +#### Ceramic Stream -```json -{ - "@context": "https://w3id.org/did/v1", - "id": "", - "verificationMethod": [], - "authentication": [], - "keyAgreement": [] +```verilog +type Event InitEvent | DataEvent | TimeEvent + +type InitEvent &Prinicipal // an inline CID containing raw principal bytes + +type DataEvent struct { + id &InitEvent + prv [&Event] // is prv needed if it's the first event after genesis? + prf [&CACAO] // capabilities used to emit this event + data &Snapshot + sig Varsig +} + +type EthereumTx // + +type BlockchainTimestamp struct { + root Link + chainID String + txType String + txHash &EthereumTx +} + +type TimeEvent struct { + id &InitEvent + prv [&DataEvent] // should always be one CID + proof &BlockchainTimestamp + path String } ``` -Now iterate though the entires in the `publicKeys` object in the Ceramic stream and do the following: +#### Streamid -* If it's a `secp256k1` key: +Generating the Ceramic streamid can be done in three steps, - * Add a `Secp256k1VerificationKey2018` to the *verificationMethod* array: +1. Generate the multidid representation of the 3ID, - ```js - { - id: "#", - type: "EcdsaSecp256k1Signature2019", - controller: "", - publicKeyBase58: "" - } - ``` + ```solidity + := + ``` - * Add a `Secp256k1SignatureAuthentication2018` to the *authentication* array: +2. Encode the multidid as an inline CID, - ```js - { - id: "#", - type: "EcdsaSecp256k1Signature2019", - controller: "", - publicKeyBase58: "" - } - ``` + ```solidity + := + ``` -* If it's a `x25519` key: +3. Encode the Streamid - * Add a `Curve25519EncryptionPublicKey` to the *verificationMethod* array: + ```solidity + := + ``` - ```js - { - id: "#", - type: "X25519KeyAgreementKey2019", - controller: "", - publicKeyBase58: "" - } - ``` +#### Create a `DataEvent` - * Add a `X25519KeyAgreementKey2019` to the *keyAgreement* array: +New data events - ```js - { - id: "#", - type: "X25519KeyAgreementKey2019", - controller: "", - publicKeyBase58: "" - } - ``` +1. Attain a key with a valid capability chain to the most recent *previous data event(s)* -##### 3IDv0 genesis +2. Create one or more `RevocationEntry` objects and update the `State` from the -Since the content of the Ceramic document for a 3IDv0 is empty at the *GenesisCommit* we create the DID document by taking the public keys in the 3IDv0 genesis object (see [Appendix A](#appendix-a)) and convert them to multicodec public keys (one `secp256k1` and one `x25519`). The key properties in the DID document should be constructed as above, with the *entry-key* being the last *15* characters of the multicodec encoded keys. + previous data event(s): -##### DID Document Metadata + 1. Write the objects to a new array and store them on the `actions` field + 2. Also append them to the `registry` map -When resolving the DID document [DID Document Metadata](https://w3c.github.io/did-core/#did-document-metadata) should be provided. When resolving a 3ID we should populate the following fields: +3. Create the `DataEvent` struct, -* `create` - should be populated using the blockchain timestamp from the first *AnchorCommit* -* `updated` - should be populated using the blockchain timestamp from the most recent *AnchorCommit* -* `versionId` - should be equal to the commit CID from the most recent *AnchorCommit* + 1. Set `id` to the principal (an inline CID containing a multidid encoded 3ID), + 2. Add the capability chain used to the `prf` field + 3. Add the previous events to the `prv` field + 4. Add the updated state to the `data` field + 5. Create a `Varsig` over the `DataEvent` with the key from (1) and add the `sig` field -#### Resolving using the `versionId` parameter +#### Validating a `DataEvent` -When the `versionId` query parameter is given as a DID is resolved it means that we should try to resolve a specific version of the DID document. The resolution process is the same except that the *AnchorCommit* we use to get the content of the document should be equal to the DocID + CID from `versionId`. In addition we should construct the *DID Document Metadata* differently. +The certification of a `DataEvent` can be validated using the following algorithm, -##### DID Document Metadata +1. The varsig validates agains the *aud* `Principal` of the referenced CACAO -* `create` - should be populated using the blockchain timestamp from the first *AnchorCommit* -* `updated` - should be populated using the blockchain timestamp from the resolved *AnchorCommit* -* `versionId` - should be equal to the commit CID from the resolved *AnchorCommit* -* `nextUpdate` - should be populated using the blockchain timestamp from the next *AnchorCommit* (if present) -* `nextVersionId` - should be equal to the commit CID from the next *AnchorCommit* (if present) +2. The multihash of the CACAO CID (caphash) is one of: -### Update + 1. CapHash is in the `Registry` and `isRevoked` is false + 2. CapHash is in the `Principal` and **not** in the `Registry` -The 3ID DID can be updated by changing the content of the Ceramic stream corresponding to the particular 3ID. Any number of public key can be added or removed from the content. Note that the *controller* of the Ceramic stream can be changed as well. This does not have any effect on the state of the DID document, but changes the DID which is in control of the 3ID document. +3. The CACAO *ability* is one or both of: -### Deactivate + 1. `"3id/add"` - the `Registry` is only allowed to grow and, new values must have `isRevoked = false` +2. `"3id/remove"` - the `Registry` can either grow or stay the same size, all modified values must have `isRevoked = true` -The 3ID can be deactivated by removing all content in the Ceramic stream of the 3ID and replacing it with one property `deactivated` set to `true`. +#### Consensus -## Security Requirements +In case of two conflicting events (two events share the same `prv` value) the event with the earliest `TimestampEvent` should be processed first. Note that this might lead to the latter event being invalid due to its delegation chain being revoked. Also, a new event emitted after the conflict must reference both branches in its `prv` and resolve any conflict of the `Registry`. -3ID derives most of its security properties from the Ceramic protocol. Most notably *censorship resistance*, *decentralization*, and requiring a minimal amount of data to be synced to completely verify the integrity of a 3ID. For more details see the Ceramic [specification](https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md). +If there is no anchor for either event yet, the `DataEvent` with the lowest binary value of its CID will win. Note that if a `TimeEvent` appears this order might change. -### Cryptographic Agility +#### Verified timestamps -As can be seen in the CRUD section, currently only `secp256k1` and `x25519` public keys are supported. This can be easily extended by using other multicodec encoded keys. The [multicodec table](https://github.com/multiformats/multicodec/blob/master/table.csv) already has support for BLS keys for example, so adding support for it would be trivial. Once good post quantum cryptography becomes more widely available extending 3ID to support that will also be fairly straight forward. +For convenience, once a `TimeEvent` has been verified the data used to verify it can be stored as a receipt. This is helpful when resolving the registry at a particular point in time using the `?versionTime=` DID URL parameter. -## Privacy Requirements +```verilog +type EthereumHeader // -See [§ 10. Privacy Considerations](https://www.w3.org/TR/did-core/#privacy-considerations) in `did-core`. +type TimestampRecipt struct { + unixtime Integer // same as block.Time + event &TimestampEvent + block &EthereumHeader + path String // ipld path in the block to find event.txHash +} +``` -## Extensibility +#### Dereferencing the Registry - The 3ID DID Method could also easily be extended to support other features specified in [did-core](https://w3c.github.io/did-core/), e.g. service endpoints. +The 3 DID resolver can [dereference](https://wiki.trustoverip.org/display/HOME/DID+URL+Resource+Parameter+Specification) the registry to a [CAR file](https://ipld.io/specs/transport/car/carv1/) which can be independently verified. This is achieved by using the `did:3:?resource=vnd.ipld.car` DID URL. Note that the `versionTime` may be used to resolve an earlier snapshot of the registry. -## Reference Implementations +### Object Capabilities -* [3id-did-provider](https://github.com/ceramicstudio/js-3id-did-provider) - wallet side implementation of the 3ID DID method -* [3id-did-resolver](https://github.com/ceramicnetwork/js-ceramic/tree/develop/packages/3id-did-resolver) - 3ID DID method resolver +The 3 DID method relies heavily on object-capabilities as they way to add and remove verification methods, as well as delegating permissions. The root capability is `did/control`, any verification method with this capability has [independent control](https://www.w3.org/TR/did-core/#independent-control) over the DID. This means that they can take any action on behalf of this DID, `*/*` is thus a equivalent of `did/control`. The `did/vm-add` and `did/vm-remove` are actions that can be taken to update the 3ID stream and thus the DID document. In the future other more specific `did/...` capabilities my be specified to define more granular actions on the DID document. -## Appendix A +``` + ┌─────────────┐ + │ did/control │ + └──▲───▲───▲──┘ + ┌────────────┘ │ └────────┐ +┌─────┴──────┐ ┌───────┴───────┐ ┌──┴──┐ +│ did/vm-add │ │ did/vm-remove │ │ */* │ +└────────────┘ └───────────────┘ └─────┘ +``` -An example 3IDv0 genesis object +#### Updating the 3ID stream +In order to make an update to the 3ID stream, one of the verification methods could delegate the following permission to a session key: ```json { - "value": { - "id": "did:3:GENESIS", - "@context": "https://w3id.org/did/v1", - "publicKey": [ - { - "id": "did:3:GENESIS#signingKey", - "type": "Secp256k1VerificationKey2018", - "publicKeyHex": "0452fbcde75f7ddd7cff18767e2b5536211f500ad474c15da8e74577a573e7a346f2192ef49a5aa0552c41f181a7950af3afdb93cafcbff18156943e3ba312e5b2" - }, - { - "id": "did:3:GENESIS#encryptionKey", - "type": "Curve25519EncryptionPublicKey", - "publicKeyBase64": "DFxR24MNHVxEDAdL2f6pPEwNDJ2p0Ldyjoo7y/ItLDc=" - }, - { - "id": "did:3:GENESIS#managementKey", - "type": "Secp256k1VerificationKey2018", - "ethereumAddress": "0x3f0bb6247d647a30f310025662b29e6fa382b61d" + "att":{ + "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { + "did/vm-add": [], + "did/vm-remove": [] } - ], - "authentication": [ - { - "type": "Secp256k1SignatureAuthentication2018", - "publicKey": "did:3:GENESIS#signingKey" + // CID of the event to append to the 3ID stream + }, + "prf": [ + { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } + // The CID of the capability that grants the key control over the 3ID + // From this the 3ID can be found, resolve revreg to see if self cap is revoked + ] +} +``` + +#### Using a 3ID in Ceramic + +In order to act on behalf of a 3ID that controls a Ceramic stream, a delegation can be created by one of the verification methods in the 3ID. Note that the `prf` field must contain a link to the capability for the verification method. + +```json +{ + "tar":{ + "ceramic://*?model=zkfif...": { + "crud/mutate": [], + "crud/read": [] } - ] - } + }, + "prf": [ + { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } + // The CID of the capability that grants the key control over the 3ID + ] } ``` +## Rationale + + + +While most DID methods include full public keys, or other DIDs as verification methods 3ID chooses to use hashes of object-capabilities as verification methods. One of the main use cases for 3ID is to connect multiple PKH DIDs into a single identifier on Ceramic. While doing so publically is fine for some use cases, the ability to do so privately is quite important for many. Using *capability hashes* enables more privacy since the DIDs that are delegated to doesn't strictly need to be revealed. It is worth noting that revealing the CACAO object when used is the simplest way to prove a capability chain. However, it is possible to create zero-knowledge proofs that only reveal the hash of the capability used and which session key was delegated to. + +### Cryptographic Agility + +The 3 DID method itself doesn't really limit what cryptography can be used. It boils down to what the system that interprets the actual object capabilities is capable of. In Ceramic this includes the following, but is not limited to, and can be extended in the future: + +* `ed25519` +* `secp256k1` +* `secp256r1` + +Once good post quantum cryptography becomes more widely available extending Ceramic to support that will also be fairly straight forward. + + +## Backwards Compatibility + + +Previous iterations of 3ID relied on the TileDocument stream type and an interpretation layer above that translated the tile contents to a DID document. That approach had numerious flaws the main one being the impossibility of privacy. This version of the spec deviates from the previous experiment in that there is a special stream type for the 3ID and that it fully relies on object-capabilities as verification methods. This is a great improvement but unfortunately it is not possible to make an upgrade in a backwards compatible manner. Instead all implementers are recommended to follow this specification only. + +## Privacy Requirements + +The 3 DID method provides a unique privacy enhancement over most other DID methods in that subject only need to reveal hashes of object-capabilities in order to use it. While the simplest way of implementing usage of the system would imply pulicly revealing these object-capabilities, it is indeed possible to create zero-knowledge proofs of the valididty of an object-capability without revealing its content. + +## Security Considerations + +3ID derives most of its security properties from the Ceramic protocol. Most notably *censorship resistance*, *decentralization*, and requiring a minimal amount of data to be synced to completely verify the integrity of a 3ID. For more details see the Ceramic [specification](https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md). + +## Reference Implementations + +Currently no reference implementation for 3ID exists. + +## Appendix A: Registrations + +This appendix contains all regsitrations necessary for the 3 DID method. + +### Verification method property + +**Property name:** `multihash` + +The multihash property is used to specify a multibase-encoded multihash. Usually this is a hash over an object-capability. + +* [Multihash specification](https://github.com/multiformats/multihash) +* [Multibase specification](https://github.com/multiformats/multibase) + +### Verification Method Type + +**Type name:** `capabilityHash` + +The capabilityHash verification method type indicates that the verification method is the hash of a CACAO. For a signature to be valid under a specific capabilityHash verification method, the proof must show that there is a valid delegation chain from the CACAO that corresponds with the given hash. In the most trivial case this can be achived by revealing the CACAO itself as part of the proof, a verifier can then check the hashed value of the CACAO. However, zero-knowledge proofs may be used to remove the need to reveal the CACAO, improving privacy for the DID subject. + +* [CAIP-74: CACAO - Chain Agnostic CApability Object](https://chainagnostic.org/CAIPs/caip-74) + +### Stream type code + +**Code:** `5` + +### Multidid code + +**Code:** `0x1b` - keccak-256 ## Copyright From 6e9e324dd898877abcbccf750f317dab5173bd89 Mon Sep 17 00:00:00 2001 From: Joel Thorstensson Date: Tue, 31 Jan 2023 14:42:37 -0600 Subject: [PATCH 2/6] Move to separate CIP --- CIPs/CIP-122.md | 454 ++++++++++++++++++++++++++++++++++++ CIPs/CIP-79/CIP-79.md | 529 ++++++++++++++---------------------------- README.md | 1 + 3 files changed, 635 insertions(+), 349 deletions(-) create mode 100644 CIPs/CIP-122.md diff --git a/CIPs/CIP-122.md b/CIPs/CIP-122.md new file mode 100644 index 0000000..4341838 --- /dev/null +++ b/CIPs/CIP-122.md @@ -0,0 +1,454 @@ +--- +cip: 122 +title: 3 DID Method +author: Joel Thorstensson (@oed) +discussions-to: https://forum.ceramic.network/t/cip-122-3-did-method +status: Draft +category: Standards +type: Core +created: 2021-02-12 +updated: 2023-01-31 +replaces: 79 +--- + +## Simple Summary + + +The 3 DID method enables users to compose multiple accounts into a single identifier. + + +## Abstract + + +With a special type of Ceramic stream 3ID enables a revocation registry that can be used to add and remove verification methods from the 3 DID method as well as revoke any capability issued by the identifier. The revocation registry is based on hashes of object-capabilities encoded as CACAO. + + +## Motivation + + +Currently in Ceramic the main accounts types are PKH DID. These are great because they enable existing wallets to be used directly with Ceramic. However, these accounts are inherently tied to a specific account and there is no way to rotate keys in a simple manner. The 3 DID method changes this by defining a DID method which works with object-capabilities and supports all DID CRUD operations. + +Furthermore, the revocation regsitry of the 3 DID method enables the DID subject to revoke any object-capability issued by the 3ID. This can be useful in case of a key compromise, e.g. for a temporary session key. + +## Specification + + +Specification goes here. + +### The did:3 identifier + +> ``` +> did:3: +> ``` + +The `` value is a `keccak-256` multihash over the CID of a CACAO object-capability, e.g. ReCap or UCAN. The value MUST be encoded as a multibase string, using `base58btc`. + +***Simple example:*** + +> ``` +> did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj +> ``` + +### CRUD Operation Definitions + +3IDs are created, updated, and deactivated by creating, notarizing, and revoking object-capabilities in the form of CACAOs. + +#### Create + +Create and sign a [SIWx](https://chainagnostic.org/CAIPs/caip-122) message where: + +- `address` - a blockchain address (e.g. `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) +- `uri` - the PKH DID for the same address (e.g. `did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) + +And resources contains the following ReCap object: + +```java +{ + "att": { + "did:3:new": { "3id/control": [] } + } +} +``` + +- *When signing this would look something like this for the user:* + + ``` + example.com wants you to sign in with your Ethereum account: + 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + + I further authorize https://example.com to perform the following + actions on my behalf: (1) "3id/control" for "did:3:new". + + URI: did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + Version: 1 + Chain ID: 1 + Nonce: n-0S6_WzA2Mj + Issued At: 2022-06-21T12:00:00.000Z + Resources: + - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 + ``` + +##### Create the DID + +```jsx +cacaoCID = ipld.put(CACAO(SIWx-message, signature)) +did = 'did:3:' + multihash(cacaoCID) +``` + +#### Read + +To read you must load a deterministic Ceramic stream to find any updates made to the 3ID. + +1. Load the revocation registry Ceramic stream + + 1. If the `?versionTime=` is specified load only the events `≤ timestamp` + +2. Read all entries where `isRevoked = false` + +3. For every CACAO multihash in the registry, as well as the 3ID identifier, + + 1. Add the following object to the `verificationMethod` property of the DID document, + + ```json + { + "id": "#", + "type": "capabilityHash", + "controller": "did:3:", + "multihash": "" + } + ``` + + 2. Add `"#"` to the following fields, + + 1. `authentication` + 2. `assertionMethod` + 3. `capabilityDelegation` + 4. `capabilityInvocation` + +##### Example DID Document + +For `did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj` with no entires in the Revocation registry, + +```json +{ + "@context": [ + "", + ] + "id": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "verificationMethod": [{ + "id": "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "type": "capabilityHash", + "controller": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "multihash": "z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" + }], + "authentication": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], + "assertionMethod": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], + "capabilityDelegation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], + "capabilityInvocation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], +} +``` + +#### Update + +##### To add a verification method: + +1. Create a new ReCap capability with an existing VM as the issuer, delegating `"3id/control"` to another DID (PKH or Key DID), and encode it as a CACAO. + + ***ReCap*** + + ```json + { + "att": { + "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { "3id/control": [] } + } + } + ``` + + - *When signing this would look something like this for the user:* + + ``` + example.com wants you to sign in with your Ethereum account: + 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + + I further authorize https://example.com to perform the following + actions on my behalf: (1) "3id/control" for "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj". + + URI: did:pkh:eip155:1:0xa05bba39b223fe8d0a0e5c4f27ead9083cb22ee3 + Version: 1 + Chain ID: 1 + Nonce: n-0S6_WzA2Mj + Issued At: 2022-06-21T12:00:00.000Z + Resources: + - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 + ``` + +2. Load the *Revocation Registry* stream + +3. Update (2) by adding the `cacao-mh` from (1) + +***To remove a verification method:*** + +1. Load the *Revocation Registry* stream +2. Update (1) by removing the `cacao-mh` that is being revoked + +#### Deactivate + +In order to deactivate a 3ID all capabilities will need to be revoked. + +### Revocation Registry + +3ID is based on a self-certifying revocation registry represented as a special type of Ceramic stream. In it any verification method belonging to the 3ID can be registered and revoked. Every update to the registry is recorded as a *Data Event*. When a new event is created is needs to include a valid delegation chain back to previous version of the registry. + +```verilog +type Prinicipal Bytes // multidid +type CACAOHash Bytes // multihash +type Varsig Bytes // varsig + +type RevocationEntry struct { + key CACAOHash + isRevoked Boolean +} representation tuple +// The registry should eventually be a HAMT or similar data structure +type Regsitry { CACAOHash : RevocationEntry } +type Snapshot struct { + registry &Regsitry + actions [RevocationEntry] +} +``` + +#### Ceramic Stream + +```verilog +type Event InitEvent | DataEvent | TimeEvent + +type InitEvent &Prinicipal // an inline CID containing raw principal bytes + +type DataEvent struct { + id &InitEvent + prv [&Event] // is prv needed if it's the first event after genesis? + prf [&CACAO] // capabilities used to emit this event + data &Snapshot + sig Varsig +} + +type EthereumTx // + +type BlockchainTimestamp struct { + root Link + chainID String + txType String + txHash &EthereumTx +} + +type TimeEvent struct { + id &InitEvent + prv [&DataEvent] // should always be one CID + proof &BlockchainTimestamp + path String +} +``` + +#### Streamid + +Generating the Ceramic streamid can be done in three steps, + +1. Generate the multidid representation of the 3ID, + + ```solidity + := + ``` + +2. Encode the multidid as an inline CID, + + ```solidity + := + ``` + +3. Encode the Streamid + + ```solidity + := + ``` + +#### Create a `DataEvent` + +New data events + +1. Attain a key with a valid capability chain to the most recent *previous data event(s)* + +2. Create one or more `RevocationEntry` objects and update the `State` from the + + previous data event(s): + + 1. Write the objects to a new array and store them on the `actions` field + 2. Also append them to the `registry` map + +3. Create the `DataEvent` struct, + + 1. Set `id` to the principal (an inline CID containing a multidid encoded 3ID), + 2. Add the capability chain used to the `prf` field + 3. Add the previous events to the `prv` field + 4. Add the updated state to the `data` field + 5. Create a `Varsig` over the `DataEvent` with the key from (1) and add the `sig` field + +#### Validating a `DataEvent` + +The certification of a `DataEvent` can be validated using the following algorithm, + +1. The varsig validates agains the *aud* `Principal` of the referenced CACAO + +2. The multihash of the CACAO CID (caphash) is one of: + + 1. CapHash is in the `Registry` and `isRevoked` is false + 2. CapHash is in the `Principal` and **not** in the `Registry` + +3. The CACAO *ability* is one or both of: + + 1. `"3id/add"` - the `Registry` is only allowed to grow and, new values must have `isRevoked = false` +2. `"3id/remove"` - the `Registry` can either grow or stay the same size, all modified values must have `isRevoked = true` + +#### Consensus + +In case of two conflicting events (two events share the same `prv` value) the event with the earliest `TimestampEvent` should be processed first. Note that this might lead to the latter event being invalid due to its delegation chain being revoked. Also, a new event emitted after the conflict must reference both branches in its `prv` and resolve any conflict of the `Registry`. + +If there is no anchor for either event yet, the `DataEvent` with the lowest binary value of its CID will win. Note that if a `TimeEvent` appears this order might change. + +#### Verified timestamps + +For convenience, once a `TimeEvent` has been verified the data used to verify it can be stored as a receipt. This is helpful when resolving the registry at a particular point in time using the `?versionTime=` DID URL parameter. + +```verilog +type EthereumHeader // + +type TimestampRecipt struct { + unixtime Integer // same as block.Time + event &TimestampEvent + block &EthereumHeader + path String // ipld path in the block to find event.txHash +} +``` + +#### Dereferencing the Registry + +The 3 DID resolver can [dereference](https://wiki.trustoverip.org/display/HOME/DID+URL+Resource+Parameter+Specification) the registry to a [CAR file](https://ipld.io/specs/transport/car/carv1/) which can be independently verified. This is achieved by using the `did:3:?resource=vnd.ipld.car` DID URL. Note that the `versionTime` may be used to resolve an earlier snapshot of the registry. + +### Object Capabilities + +The 3 DID method relies heavily on object-capabilities as they way to add and remove verification methods, as well as delegating permissions. The root capability is `did/control`, any verification method with this capability has [independent control](https://www.w3.org/TR/did-core/#independent-control) over the DID. This means that they can take any action on behalf of this DID, `*/*` is thus a equivalent of `did/control`. The `did/vm-add` and `did/vm-remove` are actions that can be taken to update the 3ID stream and thus the DID document. In the future other more specific `did/...` capabilities my be specified to define more granular actions on the DID document. + +``` + ┌─────────────┐ + │ did/control │ + └──▲───▲───▲──┘ + ┌────────────┘ │ └────────┐ +┌─────┴──────┐ ┌───────┴───────┐ ┌──┴──┐ +│ did/vm-add │ │ did/vm-remove │ │ */* │ +└────────────┘ └───────────────┘ └─────┘ +``` + +#### Updating the 3ID stream + +In order to make an update to the 3ID stream, one of the verification methods could delegate the following permission to a session key: + +```json +{ + "att":{ + "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { + "did/vm-add": [], + "did/vm-remove": [] + } + // CID of the event to append to the 3ID stream + }, + "prf": [ + { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } + // The CID of the capability that grants the key control over the 3ID + // From this the 3ID can be found, resolve revreg to see if self cap is revoked + ] +} +``` + +#### Using a 3ID in Ceramic + +In order to act on behalf of a 3ID that controls a Ceramic stream, a delegation can be created by one of the verification methods in the 3ID. Note that the `prf` field must contain a link to the capability for the verification method. + +```json +{ + "tar":{ + "ceramic://*?model=zkfif...": { + "crud/mutate": [], + "crud/read": [] + } + }, + "prf": [ + { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } + // The CID of the capability that grants the key control over the 3ID + ] +} +``` + +## Rationale + + + +While most DID methods include full public keys, or other DIDs as verification methods 3ID chooses to use hashes of object-capabilities as verification methods. One of the main use cases for 3ID is to connect multiple PKH DIDs into a single identifier on Ceramic. While doing so publically is fine for some use cases, the ability to do so privately is quite important for many. Using *capability hashes* enables more privacy since the DIDs that are delegated to doesn't strictly need to be revealed. It is worth noting that revealing the CACAO object when used is the simplest way to prove a capability chain. However, it is possible to create zero-knowledge proofs that only reveal the hash of the capability used and which session key was delegated to. + +### Cryptographic Agility + +The 3 DID method itself doesn't really limit what cryptography can be used. It boils down to what the system that interprets the actual object capabilities is capable of. In Ceramic this includes the following, but is not limited to, and can be extended in the future: + +* `ed25519` +* `secp256k1` +* `secp256r1` + +Once good post quantum cryptography becomes more widely available extending Ceramic to support that will also be fairly straight forward. + + +## Backwards Compatibility + + +Previous iterations of 3ID relied on the TileDocument stream type and an interpretation layer above that translated the tile contents to a DID document. That approach had numerious flaws the main one being the impossibility of privacy. This version of the spec deviates from the previous experiment in that there is a special stream type for the 3ID and that it fully relies on object-capabilities as verification methods. This is a great improvement but unfortunately it is not possible to make an upgrade in a backwards compatible manner. Instead all implementers are recommended to follow this specification only. + +## Privacy Requirements + +The 3 DID method provides a unique privacy enhancement over most other DID methods in that subject only need to reveal hashes of object-capabilities in order to use it. While the simplest way of implementing usage of the system would imply pulicly revealing these object-capabilities, it is indeed possible to create zero-knowledge proofs of the valididty of an object-capability without revealing its content. + +## Security Considerations + +3ID derives most of its security properties from the Ceramic protocol. Most notably *censorship resistance*, *decentralization*, and requiring a minimal amount of data to be synced to completely verify the integrity of a 3ID. For more details see the Ceramic [specification](https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md). + +## Reference Implementations + +Currently no reference implementation for 3ID exists. + +## Appendix A: Registrations + +This appendix contains all regsitrations necessary for the 3 DID method. + +### Verification method property + +**Property name:** `multihash` + +The multihash property is used to specify a multibase-encoded multihash. Usually this is a hash over an object-capability. + +* [Multihash specification](https://github.com/multiformats/multihash) +* [Multibase specification](https://github.com/multiformats/multibase) + +### Verification Method Type + +**Type name:** `capabilityHash` + +The capabilityHash verification method type indicates that the verification method is the hash of a CACAO. For a signature to be valid under a specific capabilityHash verification method, the proof must show that there is a valid delegation chain from the CACAO that corresponds with the given hash. In the most trivial case this can be achived by revealing the CACAO itself as part of the proof, a verifier can then check the hashed value of the CACAO. However, zero-knowledge proofs may be used to remove the need to reveal the CACAO, improving privacy for the DID subject. + +* [CAIP-74: CACAO - Chain Agnostic CApability Object](https://chainagnostic.org/CAIPs/caip-74) + +### Stream type code + +**Code:** `5` + +### Multidid code + +**Code:** `0x1b` - keccak-256 + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/CIPs/CIP-79/CIP-79.md b/CIPs/CIP-79/CIP-79.md index 7bbb021..4fcda28 100644 --- a/CIPs/CIP-79/CIP-79.md +++ b/CIPs/CIP-79/CIP-79.md @@ -1,452 +1,283 @@ --- cip: 79 -title: 3 DID Method Specification +title: 3ID DID Method Specification author: Joel Thorstensson (@oed) discussions-to: https://github.com/ceramicnetwork/CIP/issues/80 -status: Draft +status: Superseded category: Standards -type: Core +type: RFC created: 2021-02-12 -updated: 2023-01-13 +updated: 2023-01-31 +Superseded By: 122 --- -## Simple Summary +# 3ID DID Method Specification - -The 3 DID method enables users to compose multiple accounts into a signle identifier. +3ID is a DID method that is implemented natively on Ceramic. It uses the Tile Document StreamType to create a mutable stream that stores the information which makes up the DID document for the 3ID. The Tile Document StreamType supports secure key rotation for 3IDs since its updates must be anchored into a blockchain, providing explicit versions and *proof-of-publication* at specific points in time (blockheights). This means that 3ID inherits this property. +## DID Method Name -## Abstract +The name string that shall identify this DID method is: `3`. - -With a special type of Ceramic stream 3ID enables a revocation registry that can be used to add and remove verification methods from the 3 DID method as well as revoke any capability issued by the identifier. The revocation registry is based on hashes of object-capabilities encoded as CACAO. +A DID that uses this method MUST begin with the following prefix: `did:3`. Per the [DID specification](https://w3c.github.io/did-core/), this string MUST be in lowercase. The remainder of the DID, after the prefix, is specified below. +## Method Specific Identifier -## Motivation +There are two versions of 3IDs. Both versions use a Ceramic Tile Document StreamType as a way to update the DID document. 3IDv1 is the most recent version, however 3IDv0 is supported for legacy reasons. If you are creating new 3IDs you should always use 3IDv1. Both versions are always encoded using multibase. To determine if it's v1 or v0, first convert the multibase string into a byte array. If the first varint is `0x01` it's a 3IDv0, and if the first varint is `0xce` it's a 3IDv1. - -Currently in Ceramic the main accounts types are PKH DID. These are great because they enable existing wallets to be used directly with Ceramic. However, these accounts are inherently tied to a specific account and there is no way to rotate keys in a simple manner. The 3 DID method changes this by defining a DID method which works with object-capabilities and supports all DID CRUD operations. +### 3IDv1 -Furthermore, the revocation regsitry of the 3 DID method enables the DID subject to revoke any object-capability issued by the 3ID. This can be useful in case of a key compromise, e.g. for a temporary session key. +The method specific identifier for 3IDv1 is simply a Ceramic StreamID. The StreamID used refers to the Ceramic stream which contains the information needed to construct the DID Document upon resolution. StreamIDs are encoded according to [CIP-59](https://github.com/ceramicnetwork/CIP/blob/master/CIPs/CIP-59/CIP-59.md). -## Specification - - -Specification goes here. - -### The did:3 identifier - -> ``` -> did:3: -> ``` - -The `` value is a `keccak-256` multihash over the CID of a CACAO object-capability, e.g. ReCap or UCAN. The value MUST be encoded as a multibase string, using `base58btc`. - -***Simple example:*** - -> ``` -> did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj -> ``` - -### CRUD Operation Definitions - -3IDs are created, updated, and deactivated by creating, notarizing, and revoking object-capabilities in the form of CACAOs. - -#### Create - -Create and sign a [SIWx](https://chainagnostic.org/CAIPs/caip-122) message where: - -- `address` - a blockchain address (e.g. `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) -- `uri` - the PKH DID for the same address (e.g. `did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) - -And resources contains the following ReCap object: - -```java -{ - "att": { - "did:3:new": { "3id/control": [] } - } -} ``` - -- *When signing this would look something like this for the user:* - - ``` - example.com wants you to sign in with your Ethereum account: - 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - - I further authorize https://example.com to perform the following - actions on my behalf: (1) "3id/control" for "did:3:new". - - URI: did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - Version: 1 - Chain ID: 1 - Nonce: n-0S6_WzA2Mj - Issued At: 2022-06-21T12:00:00.000Z - Resources: - - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 - ``` - -##### Create the DID - -```jsx -cacaoCID = ipld.put(CACAO(SIWx-message, signature)) -did = 'did:3:' + multihash(cacaoCID) +3idv1 = "did:3:" ``` -#### Read +#### Example -To read you must load a deterministic Ceramic stream to find any updates made to the 3ID. +```sh +did:3:kjzl6cwe1jw149tlplc4bgnpn1v4uwk9rg9jkvijx0u0zmfa97t69dnqibqa2as +``` -1. Load the revocation registry Ceramic stream +### 3IDv0 - 1. If the `?versionTime=` is specified load only the events `≤ timestamp` +The method specific identifier for 3IDv0 is a [CID](https://github.com/multiformats/cid) as produced by the [IPLD](https://github.com/ipld/specs) codec [dag-cbor](https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-cbor.md). -2. Read all entries where `isRevoked = false` +``` +3idv0 = "did:3:" +``` -3. For every CACAO multihash in the registry, as well as the 3ID identifier, +#### Example - 1. Add the following object to the `verificationMethod` property of the DID document, - - ```json - { - "id": "#", - "type": "capabilityHash", - "controller": "did:3:", - "multihash": "" - } - ``` - - 2. Add `"#"` to the following fields, - - 1. `authentication` - 2. `assertionMethod` - 3. `capabilityDelegation` - 4. `capabilityInvocation` +```sh +did:3:bafyreiffkeeq4wq2htejqla2is5ognligi4lvjhwrpqpl2kazjdoecmugi +``` -##### Example DID Document +## CRUD Operation Definitions -For `did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj` with no entires in the Revocation registry, +In this section the CRUD operations for a 3ID DID are defined. -```json -{ - "@context": [ - "", - ] - "id": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", - "verificationMethod": [{ - "id": "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", - "type": "capabilityHash", - "controller": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", - "multihash": "z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" - }], - "authentication": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], - "assertionMethod": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], - "capabilityDelegation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], - "capabilityInvocation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], -} -``` +### Create -#### Update +A `3` DID is created by simply creating a stream that conforms to the [`tile document`](https://github.com/ceramicnetwork/CIP/blob/master/CIPs/CIP-8/CIP-8.md) StreamType. The [`tile document`](https://github.com/ceramicnetwork/CIP/blob/master/CIPs/CIP-8/CIP-8.md) takes a DID as the *controller*, and it's recommended that a `did:key` is used. The *controller* is the DID which is allowed to update the stream. The *family* of the stream is set to `3id`, and the *deterministic* flag is set to `true`. -##### To add a verification method: +Now the content of the stream should consist of a JSON object with one property *publicKeys*. These public keys will be allowed to sign messages on behalf of the 3ID, or decrypt messages encrypted to the 3ID. The value of this property should be an object where the value is a [multicodec](https://github.com/multiformats/multicodec/) + multibase(*base58btc*) encoded public key, the key for any given key should be the last *15* characters of the encoded public key. -1. Create a new ReCap capability with an existing VM as the issuer, delegating `"3id/control"` to another DID (PKH or Key DID), and encode it as a CACAO. +The 3ID DID method supports any type of public key that can be encoded using multicodec which can easily be extended to support quantum resistant signature and encryption schemes in the future. - ***ReCap*** +#### Example - ```json - { - "att": { - "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { "3id/control": [] } - } - } - ``` +Below you can see an example of how to create a 3ID using the Ceramic javascript api. - - *When signing this would look something like this for the user:* +```js +const doc = await ceramic.createDocument({ + metadata: { + controllers: ['did:key:zQ3shQNcackrTByiYaPGso1Nt7b6r1gSMg4XXBmavzvTMqX1h'], // secp256k1 did:key + family: '3id' + }, + content: { + publicKeys: { + "XQCT2xJHsdY6iJH": "z6LSqKWh3XQ7AfsJuE2KR23cozEut8D5CXQCT2xJHsdY6iJH", // x22519 public key + "yh27jTt7Ny2Pwdy": "zQ3shrMGEKAjUTMmvDkcZ7Y3x9XnVjTH3myh27jTt7Ny2Pwdy", // secp256k1 public key + } + }, + deterministic: true +}) - ``` - example.com wants you to sign in with your Ethereum account: - 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - - I further authorize https://example.com to perform the following - actions on my behalf: (1) "3id/control" for "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj". - - URI: did:pkh:eip155:1:0xa05bba39b223fe8d0a0e5c4f27ead9083cb22ee3 - Version: 1 - Chain ID: 1 - Nonce: n-0S6_WzA2Mj - Issued At: 2022-06-21T12:00:00.000Z - Resources: - - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 - ``` +const didString = `did:3:${doc.id}` +``` -2. Load the *Revocation Registry* stream +### Read/Verify -3. Update (2) by adding the `cacao-mh` from (1) +Resolving a 3ID is quite straight forward. It is done by taking the StreamID from the method specific identifier, looking up the referred stream using Ceramic, and converting the content of the stream into a DID document. -***To remove a verification method:*** +#### Loading 3IDv1 stream -1. Load the *Revocation Registry* stream -2. Update (1) by removing the `cacao-mh` that is being revoked +To load a 3IDv1 document simply take the StreamID from the method specific identifier and load the stream from ceramic. -#### Deactivate +#### Loading 3IDv0 document -In order to deactivate a 3ID all capabilities will need to be revoked. +To load a 3IDv0 document, first take the CID from the method specific identifier and load the corresponding object from the IPFS network. The resolved object will contain a `publicKey` property which has an array of public key objects (see [Appendix A](#appendix-a)). -### Revocation Registry +Now find the key with an id that ends in `#signingKey` and convert it to a multicodec encoded key (in compressed format), then use it as a `did:key` and look up the ceramic document which has this key as the *controller* and *family* set to `3id`, using the *deterministic* flag. Below you can see the code to do this with the javascript Ceramic api. -3ID is based on a self-certifying revocation registry represented as a special type of Ceramic stream. In it any verification method belonging to the 3ID can be registered and revoked. Every update to the registry is recorded as a *Data Event*. When a new event is created is needs to include a valid delegation chain back to previous version of the registry. -```verilog -type Prinicipal Bytes // multidid -type CACAOHash Bytes // multihash -type Varsig Bytes // varsig -type RevocationEntry struct { - key CACAOHash - isRevoked Boolean -} representation tuple -// The registry should eventually be a HAMT or similar data structure -type Regsitry { CACAOHash : RevocationEntry } -type Snapshot struct { - registry &Regsitry - actions [RevocationEntry] -} +```js +const doc = await ceramic.createDocument({ + metadata: { + controllers: [didKey], // secp256k1 did:key + family: '3id' + }, + deterministic: true +}) ``` -#### Ceramic Stream +#### Converting the loaded Ceramic stream to the DID document -```verilog -type Event InitEvent | DataEvent | TimeEvent +Once we have the stream loaded, load the latest *AnchorCommit* in the stream (the latest commit that was anchored to a blockchain). Then get the content of the stream at this `AnchorCommit`, which will look something like this: -type InitEvent &Prinicipal // an inline CID containing raw principal bytes - -type DataEvent struct { - id &InitEvent - prv [&Event] // is prv needed if it's the first event after genesis? - prf [&CACAO] // capabilities used to emit this event - data &Snapshot - sig Varsig +```json +{ + "publicKeys": { + "j9uh8iKHSDSLat4": "zQ3shaLgXkpEXt7He5mogBxFfib5cE2kv9j9uh8iKHSDSLat4", + "qYfZN2QNDgjJpaL": "z6LSnTyV1nSWfMmfV1PoRmo3enhDnfqfFqYfZN2QNDgjJpaL" + } } +``` -type EthereumTx // +To convert this into a DID document first create an empty DID document: -type BlockchainTimestamp struct { - root Link - chainID String - txType String - txHash &EthereumTx -} - -type TimeEvent struct { - id &InitEvent - prv [&DataEvent] // should always be one CID - proof &BlockchainTimestamp - path String +```json +{ + "@context": "https://w3id.org/did/v1", + "id": "", + "verificationMethod": [], + "authentication": [], + "keyAgreement": [] } ``` -#### Streamid +Now iterate though the entires in the `publicKeys` object in the Ceramic stream and do the following: -Generating the Ceramic streamid can be done in three steps, +* If it's a `secp256k1` key: -1. Generate the multidid representation of the 3ID, + * Add a `Secp256k1VerificationKey2018` to the *verificationMethod* array: - ```solidity - := - ``` + ```js + { + id: "#", + type: "EcdsaSecp256k1Signature2019", + controller: "", + publicKeyBase58: "" + } + ``` -2. Encode the multidid as an inline CID, + * Add a `Secp256k1SignatureAuthentication2018` to the *authentication* array: - ```solidity - := - ``` + ```js + { + id: "#", + type: "EcdsaSecp256k1Signature2019", + controller: "", + publicKeyBase58: "" + } + ``` -3. Encode the Streamid +* If it's a `x25519` key: - ```solidity - := - ``` + * Add a `Curve25519EncryptionPublicKey` to the *verificationMethod* array: -#### Create a `DataEvent` + ```js + { + id: "#", + type: "X25519KeyAgreementKey2019", + controller: "", + publicKeyBase58: "" + } + ``` -New data events + * Add a `X25519KeyAgreementKey2019` to the *keyAgreement* array: -1. Attain a key with a valid capability chain to the most recent *previous data event(s)* + ```js + { + id: "#", + type: "X25519KeyAgreementKey2019", + controller: "", + publicKeyBase58: "" + } + ``` -2. Create one or more `RevocationEntry` objects and update the `State` from the +##### 3IDv0 genesis - previous data event(s): +Since the content of the Ceramic document for a 3IDv0 is empty at the *GenesisCommit* we create the DID document by taking the public keys in the 3IDv0 genesis object (see [Appendix A](#appendix-a)) and convert them to multicodec public keys (one `secp256k1` and one `x25519`). The key properties in the DID document should be constructed as above, with the *entry-key* being the last *15* characters of the multicodec encoded keys. - 1. Write the objects to a new array and store them on the `actions` field - 2. Also append them to the `registry` map +##### DID Document Metadata -3. Create the `DataEvent` struct, +When resolving the DID document [DID Document Metadata](https://w3c.github.io/did-core/#did-document-metadata) should be provided. When resolving a 3ID we should populate the following fields: - 1. Set `id` to the principal (an inline CID containing a multidid encoded 3ID), - 2. Add the capability chain used to the `prf` field - 3. Add the previous events to the `prv` field - 4. Add the updated state to the `data` field - 5. Create a `Varsig` over the `DataEvent` with the key from (1) and add the `sig` field +* `create` - should be populated using the blockchain timestamp from the first *AnchorCommit* +* `updated` - should be populated using the blockchain timestamp from the most recent *AnchorCommit* +* `versionId` - should be equal to the commit CID from the most recent *AnchorCommit* -#### Validating a `DataEvent` +#### Resolving using the `versionId` parameter -The certification of a `DataEvent` can be validated using the following algorithm, +When the `versionId` query parameter is given as a DID is resolved it means that we should try to resolve a specific version of the DID document. The resolution process is the same except that the *AnchorCommit* we use to get the content of the document should be equal to the DocID + CID from `versionId`. In addition we should construct the *DID Document Metadata* differently. -1. The varsig validates agains the *aud* `Principal` of the referenced CACAO +##### DID Document Metadata -2. The multihash of the CACAO CID (caphash) is one of: +* `create` - should be populated using the blockchain timestamp from the first *AnchorCommit* +* `updated` - should be populated using the blockchain timestamp from the resolved *AnchorCommit* +* `versionId` - should be equal to the commit CID from the resolved *AnchorCommit* +* `nextUpdate` - should be populated using the blockchain timestamp from the next *AnchorCommit* (if present) +* `nextVersionId` - should be equal to the commit CID from the next *AnchorCommit* (if present) - 1. CapHash is in the `Registry` and `isRevoked` is false - 2. CapHash is in the `Principal` and **not** in the `Registry` +### Update -3. The CACAO *ability* is one or both of: +The 3ID DID can be updated by changing the content of the Ceramic stream corresponding to the particular 3ID. Any number of public key can be added or removed from the content. Note that the *controller* of the Ceramic stream can be changed as well. This does not have any effect on the state of the DID document, but changes the DID which is in control of the 3ID document. - 1. `"3id/add"` - the `Registry` is only allowed to grow and, new values must have `isRevoked = false` -2. `"3id/remove"` - the `Registry` can either grow or stay the same size, all modified values must have `isRevoked = true` +### Deactivate -#### Consensus +The 3ID can be deactivated by removing all content in the Ceramic stream of the 3ID and replacing it with one property `deactivated` set to `true`. -In case of two conflicting events (two events share the same `prv` value) the event with the earliest `TimestampEvent` should be processed first. Note that this might lead to the latter event being invalid due to its delegation chain being revoked. Also, a new event emitted after the conflict must reference both branches in its `prv` and resolve any conflict of the `Registry`. +## Security Requirements -If there is no anchor for either event yet, the `DataEvent` with the lowest binary value of its CID will win. Note that if a `TimeEvent` appears this order might change. +3ID derives most of its security properties from the Ceramic protocol. Most notably *censorship resistance*, *decentralization*, and requiring a minimal amount of data to be synced to completely verify the integrity of a 3ID. For more details see the Ceramic [specification](https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md). -#### Verified timestamps +### Cryptographic Agility -For convenience, once a `TimeEvent` has been verified the data used to verify it can be stored as a receipt. This is helpful when resolving the registry at a particular point in time using the `?versionTime=` DID URL parameter. +As can be seen in the CRUD section, currently only `secp256k1` and `x25519` public keys are supported. This can be easily extended by using other multicodec encoded keys. The [multicodec table](https://github.com/multiformats/multicodec/blob/master/table.csv) already has support for BLS keys for example, so adding support for it would be trivial. Once good post quantum cryptography becomes more widely available extending 3ID to support that will also be fairly straight forward. -```verilog -type EthereumHeader // +## Privacy Requirements -type TimestampRecipt struct { - unixtime Integer // same as block.Time - event &TimestampEvent - block &EthereumHeader - path String // ipld path in the block to find event.txHash -} -``` +See [§ 10. Privacy Considerations](https://www.w3.org/TR/did-core/#privacy-considerations) in `did-core`. -#### Dereferencing the Registry +## Extensibility -The 3 DID resolver can [dereference](https://wiki.trustoverip.org/display/HOME/DID+URL+Resource+Parameter+Specification) the registry to a [CAR file](https://ipld.io/specs/transport/car/carv1/) which can be independently verified. This is achieved by using the `did:3:?resource=vnd.ipld.car` DID URL. Note that the `versionTime` may be used to resolve an earlier snapshot of the registry. + The 3ID DID Method could also easily be extended to support other features specified in [did-core](https://w3c.github.io/did-core/), e.g. service endpoints. -### Object Capabilities +## Reference Implementations -The 3 DID method relies heavily on object-capabilities as they way to add and remove verification methods, as well as delegating permissions. The root capability is `did/control`, any verification method with this capability has [independent control](https://www.w3.org/TR/did-core/#independent-control) over the DID. This means that they can take any action on behalf of this DID, `*/*` is thus a equivalent of `did/control`. The `did/vm-add` and `did/vm-remove` are actions that can be taken to update the 3ID stream and thus the DID document. In the future other more specific `did/...` capabilities my be specified to define more granular actions on the DID document. +* [3id-did-provider](https://github.com/ceramicstudio/js-3id-did-provider) - wallet side implementation of the 3ID DID method +* [3id-did-resolver](https://github.com/ceramicnetwork/js-ceramic/tree/develop/packages/3id-did-resolver) - 3ID DID method resolver -``` - ┌─────────────┐ - │ did/control │ - └──▲───▲───▲──┘ - ┌────────────┘ │ └────────┐ -┌─────┴──────┐ ┌───────┴───────┐ ┌──┴──┐ -│ did/vm-add │ │ did/vm-remove │ │ */* │ -└────────────┘ └───────────────┘ └─────┘ -``` +## Appendix A -#### Updating the 3ID stream +An example 3IDv0 genesis object -In order to make an update to the 3ID stream, one of the verification methods could delegate the following permission to a session key: ```json { - "att":{ - "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { - "did/vm-add": [], - "did/vm-remove": [] + "value": { + "id": "did:3:GENESIS", + "@context": "https://w3id.org/did/v1", + "publicKey": [ + { + "id": "did:3:GENESIS#signingKey", + "type": "Secp256k1VerificationKey2018", + "publicKeyHex": "0452fbcde75f7ddd7cff18767e2b5536211f500ad474c15da8e74577a573e7a346f2192ef49a5aa0552c41f181a7950af3afdb93cafcbff18156943e3ba312e5b2" + }, + { + "id": "did:3:GENESIS#encryptionKey", + "type": "Curve25519EncryptionPublicKey", + "publicKeyBase64": "DFxR24MNHVxEDAdL2f6pPEwNDJ2p0Ldyjoo7y/ItLDc=" + }, + { + "id": "did:3:GENESIS#managementKey", + "type": "Secp256k1VerificationKey2018", + "ethereumAddress": "0x3f0bb6247d647a30f310025662b29e6fa382b61d" } - // CID of the event to append to the 3ID stream - }, - "prf": [ - { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } - // The CID of the capability that grants the key control over the 3ID - // From this the 3ID can be found, resolve revreg to see if self cap is revoked - ] -} -``` - -#### Using a 3ID in Ceramic - -In order to act on behalf of a 3ID that controls a Ceramic stream, a delegation can be created by one of the verification methods in the 3ID. Note that the `prf` field must contain a link to the capability for the verification method. - -```json -{ - "tar":{ - "ceramic://*?model=zkfif...": { - "crud/mutate": [], - "crud/read": [] + ], + "authentication": [ + { + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "did:3:GENESIS#signingKey" } - }, - "prf": [ - { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } - // The CID of the capability that grants the key control over the 3ID - ] + ] + } } ``` -## Rationale - - - -While most DID methods include full public keys, or other DIDs as verification methods 3ID chooses to use hashes of object-capabilities as verification methods. One of the main use cases for 3ID is to connect multiple PKH DIDs into a single identifier on Ceramic. While doing so publically is fine for some use cases, the ability to do so privately is quite important for many. Using *capability hashes* enables more privacy since the DIDs that are delegated to doesn't strictly need to be revealed. It is worth noting that revealing the CACAO object when used is the simplest way to prove a capability chain. However, it is possible to create zero-knowledge proofs that only reveal the hash of the capability used and which session key was delegated to. - -### Cryptographic Agility - -The 3 DID method itself doesn't really limit what cryptography can be used. It boils down to what the system that interprets the actual object capabilities is capable of. In Ceramic this includes the following, but is not limited to, and can be extended in the future: - -* `ed25519` -* `secp256k1` -* `secp256r1` - -Once good post quantum cryptography becomes more widely available extending Ceramic to support that will also be fairly straight forward. - - -## Backwards Compatibility - - -Previous iterations of 3ID relied on the TileDocument stream type and an interpretation layer above that translated the tile contents to a DID document. That approach had numerious flaws the main one being the impossibility of privacy. This version of the spec deviates from the previous experiment in that there is a special stream type for the 3ID and that it fully relies on object-capabilities as verification methods. This is a great improvement but unfortunately it is not possible to make an upgrade in a backwards compatible manner. Instead all implementers are recommended to follow this specification only. - -## Privacy Requirements - -The 3 DID method provides a unique privacy enhancement over most other DID methods in that subject only need to reveal hashes of object-capabilities in order to use it. While the simplest way of implementing usage of the system would imply pulicly revealing these object-capabilities, it is indeed possible to create zero-knowledge proofs of the valididty of an object-capability without revealing its content. - -## Security Considerations - -3ID derives most of its security properties from the Ceramic protocol. Most notably *censorship resistance*, *decentralization*, and requiring a minimal amount of data to be synced to completely verify the integrity of a 3ID. For more details see the Ceramic [specification](https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md). - -## Reference Implementations - -Currently no reference implementation for 3ID exists. - -## Appendix A: Registrations - -This appendix contains all regsitrations necessary for the 3 DID method. - -### Verification method property - -**Property name:** `multihash` - -The multihash property is used to specify a multibase-encoded multihash. Usually this is a hash over an object-capability. - -* [Multihash specification](https://github.com/multiformats/multihash) -* [Multibase specification](https://github.com/multiformats/multibase) - -### Verification Method Type - -**Type name:** `capabilityHash` - -The capabilityHash verification method type indicates that the verification method is the hash of a CACAO. For a signature to be valid under a specific capabilityHash verification method, the proof must show that there is a valid delegation chain from the CACAO that corresponds with the given hash. In the most trivial case this can be achived by revealing the CACAO itself as part of the proof, a verifier can then check the hashed value of the CACAO. However, zero-knowledge proofs may be used to remove the need to reveal the CACAO, improving privacy for the DID subject. - -* [CAIP-74: CACAO - Chain Agnostic CApability Object](https://chainagnostic.org/CAIPs/caip-74) - -### Stream type code - -**Code:** `5` - -### Multidid code - -**Code:** `0x1b` - keccak-256 ## Copyright diff --git a/README.md b/README.md index 6862587..536ee27 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ An editor will ask if anyone objects to it being finalized. If the editor decide - `Accepted (Core)`: an CIP of type Core that has been accepted by the core devs to be included in a future network upgrade. - `Final (Core)`: an CIP of type Core that has already been released in a network upgrade. - `Final (non-Core)`: a non-core CIP that has met all criteria and is finished. +- `Superseded`: has been superseded by a new CIP, should also include a `Superseded By` field pointing to the new CIP. # Editors - Michael Sena ([@michaelsena](http://github.com/michaelsena)) From 5f72d8779c0a6a8a136bd19e9135f674acadf939 Mon Sep 17 00:00:00 2001 From: Joel Thorstensson Date: Tue, 11 Apr 2023 17:47:13 +0100 Subject: [PATCH 3/6] Make 3ID purely generative --- CIPs/CIP-122.md | 337 ++++++++++-------------------------------------- 1 file changed, 68 insertions(+), 269 deletions(-) diff --git a/CIPs/CIP-122.md b/CIPs/CIP-122.md index 4341838..4e99ec3 100644 --- a/CIPs/CIP-122.md +++ b/CIPs/CIP-122.md @@ -14,26 +14,24 @@ replaces: 79 ## Simple Summary -The 3 DID method enables users to compose multiple accounts into a single identifier. +The 3 DID method enables users to create ephemeral or long lived identities. ## Abstract -With a special type of Ceramic stream 3ID enables a revocation registry that can be used to add and remove verification methods from the 3 DID method as well as revoke any capability issued by the identifier. The revocation registry is based on hashes of object-capabilities encoded as CACAO. + +The 3 DID method, or 3ID for short, is a simple purely generative DID method. It is designed to be combined with a CACAO based object capability system which enables the creation of both private and composable identities. While 3ID enables the creation of simple, short lived identities, the combination of the 3 DID method with [CIP-XXX - CapReg]() affords the subject the ability to delegate control of a 3ID to mutltiple other DIDs all while maintaining the ability to easily revoke access. ## Motivation -Currently in Ceramic the main accounts types are PKH DID. These are great because they enable existing wallets to be used directly with Ceramic. However, these accounts are inherently tied to a specific account and there is no way to rotate keys in a simple manner. The 3 DID method changes this by defining a DID method which works with object-capabilities and supports all DID CRUD operations. - -Furthermore, the revocation regsitry of the 3 DID method enables the DID subject to revoke any object-capability issued by the 3ID. This can be useful in case of a key compromise, e.g. for a temporary session key. +Currently in Ceramic the main accounts types are PKH DID. These are great because they enable existing wallets to be used directly with Ceramic. However, these accounts are inherently tied to a specific account and there is no way to maintain privacy. It's also no way to maintain a single long lived identity since specific accounts may only be used for a certain amount of time. ## Specification -Specification goes here. ### The did:3 identifier @@ -41,55 +39,59 @@ Specification goes here. > did:3: > ``` -The `` value is a `keccak-256` multihash over the CID of a CACAO object-capability, e.g. ReCap or UCAN. The value MUST be encoded as a multibase string, using `base58btc`. +The `` value is a `sha2-256` multihash over the CID of a CACAO object-capability. The object capability in question MUST be a SIWx message including a ReCap delegation as specified below. The value MUST be encoded as a multibase string, using `base58btc`. ***Simple example:*** > ``` -> did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj +> did:3:zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ > ``` ### CRUD Operation Definitions -3IDs are created, updated, and deactivated by creating, notarizing, and revoking object-capabilities in the form of CACAOs. +3IDs are created by creating a SIWx object-capability. Updating and deactivating is not supported natively in the DID method, but a 3ID can be combined with a [CapReg]() to delegate permissions to other DIDs or revoke any capability (including the capability that created the 3ID in the first place). #### Create Create and sign a [SIWx](https://chainagnostic.org/CAIPs/caip-122) message where: - `address` - a blockchain address (e.g. `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) -- `uri` - the PKH DID for the same address (e.g. `did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) +- `uri` - either a Key DID or the identifier for a new 3 DID (e.g. `did:3:new`) + +If the `uri` contains a Key DID, this key can be used directly to take any actions on behalf of the newly created 3ID. Otherwise if the `uri` contains the new 3 DID identifier it indicates that no delegation is done at this point in time. Note that the issuer, as defined by the `address`, always have full control permissions over the newly created 3ID. And resources contains the following ReCap object: ```java { "att": { - "did:3:new": { "3id/control": [] } + "did:3:new": { "*": [{}] } } } ``` -- *When signing this would look something like this for the user:* - - ``` - example.com wants you to sign in with your Ethereum account: - 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - - I further authorize https://example.com to perform the following - actions on my behalf: (1) "3id/control" for "did:3:new". - - URI: did:pkh:eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - Version: 1 - Chain ID: 1 - Nonce: n-0S6_WzA2Mj - Issued At: 2022-06-21T12:00:00.000Z - Resources: - - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 - ``` +When signing this would look something like this for the user: + +``` +example.com wants you to sign in with your Ethereum account: +0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + +I further authorize https://example.com to perform the following +actions on my behalf: (1) "*" for "did:3:new". + +URI: did:3:new +Version: 1 +Chain ID: 1 +Nonce: n-0S6_WzA2Mj +Issued At: 2022-06-21T12:00:00.000Z +Resources: +- urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 +``` ##### Create the DID +Pseudo-code for how to compute the 3ID identifier. + ```jsx cacaoCID = ipld.put(CACAO(SIWx-message, signature)) did = 'did:3:' + multihash(cacaoCID) @@ -97,279 +99,78 @@ did = 'did:3:' + multihash(cacaoCID) #### Read -To read you must load a deterministic Ceramic stream to find any updates made to the 3ID. - -1. Load the revocation registry Ceramic stream - - 1. If the `?versionTime=` is specified load only the events `≤ timestamp` - -2. Read all entries where `isRevoked = false` - -3. For every CACAO multihash in the registry, as well as the 3ID identifier, - - 1. Add the following object to the `verificationMethod` property of the DID document, - - ```json - { - "id": "#", - "type": "capabilityHash", - "controller": "did:3:", - "multihash": "" - } - ``` - - 2. Add `"#"` to the following fields, - - 1. `authentication` - 2. `assertionMethod` - 3. `capabilityDelegation` - 4. `capabilityInvocation` +When reading a 3 DID, the DID document is simply created deterministically from the identifier. ##### Example DID Document -For `did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj` with no entires in the Revocation registry, +For `did:3:zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ` the DID document looks as follows, ```json { "@context": [ "", ] - "id": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "id": "did:3:zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ", "verificationMethod": [{ - "id": "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", + "id": "#0", "type": "capabilityHash", - "controller": "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj", - "multihash": "z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" + "controller": "did:3:zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ", + "multihash": "zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ" }], - "authentication": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], - "assertionMethod": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], - "capabilityDelegation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], - "capabilityInvocation": [ "#z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj" ], + "authentication": [ "#0" ], + "assertionMethod": [ "#0" ], + "capabilityDelegation": [ "#0" ], + "capabilityInvocation": [ "#0" ], } ``` -#### Update - -##### To add a verification method: - -1. Create a new ReCap capability with an existing VM as the issuer, delegating `"3id/control"` to another DID (PKH or Key DID), and encode it as a CACAO. - - ***ReCap*** - - ```json - { - "att": { - "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { "3id/control": [] } - } - } - ``` - - - *When signing this would look something like this for the user:* - - ``` - example.com wants you to sign in with your Ethereum account: - 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - - I further authorize https://example.com to perform the following - actions on my behalf: (1) "3id/control" for "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj". - - URI: did:pkh:eip155:1:0xa05bba39b223fe8d0a0e5c4f27ead9083cb22ee3 - Version: 1 - Chain ID: 1 - Nonce: n-0S6_WzA2Mj - Issued At: 2022-06-21T12:00:00.000Z - Resources: - - urn:recap:example:eyJkZWYiOlsicmVhZCJdLCJ0YXIiOnsibXkucmVzb3VyY2UuMSI6WyJhcHBlbmQiLCJkZWxldGUiXSwibXkucmVzb3VyY2UuMiI6WyJhcHBlbmQiXSwibXkucmVzb3VyY2UuMyI6WyJhcHBlbmQiXX19 - ``` +See Appendix A for the registrations of `capabilityHash` and `multihash`. -2. Load the *Revocation Registry* stream - -3. Update (2) by adding the `cacao-mh` from (1) - -***To remove a verification method:*** +#### Update -1. Load the *Revocation Registry* stream -2. Update (1) by removing the `cacao-mh` that is being revoked +Updating a 3 DID is not possible. Note however that a 3 DID may be used together with object capabilities and a revocation registry, for example [CapReg](). In this case it would be possible to delegate permissions to any new DID or revoke any capability. #### Deactivate -In order to deactivate a 3ID all capabilities will need to be revoked. - -### Revocation Registry - -3ID is based on a self-certifying revocation registry represented as a special type of Ceramic stream. In it any verification method belonging to the 3ID can be registered and revoked. Every update to the registry is recorded as a *Data Event*. When a new event is created is needs to include a valid delegation chain back to previous version of the registry. - -```verilog -type Prinicipal Bytes // multidid -type CACAOHash Bytes // multihash -type Varsig Bytes // varsig - -type RevocationEntry struct { - key CACAOHash - isRevoked Boolean -} representation tuple -// The registry should eventually be a HAMT or similar data structure -type Regsitry { CACAOHash : RevocationEntry } -type Snapshot struct { - registry &Regsitry - actions [RevocationEntry] -} -``` - -#### Ceramic Stream - -```verilog -type Event InitEvent | DataEvent | TimeEvent - -type InitEvent &Prinicipal // an inline CID containing raw principal bytes - -type DataEvent struct { - id &InitEvent - prv [&Event] // is prv needed if it's the first event after genesis? - prf [&CACAO] // capabilities used to emit this event - data &Snapshot - sig Varsig -} - -type EthereumTx // - -type BlockchainTimestamp struct { - root Link - chainID String - txType String - txHash &EthereumTx -} - -type TimeEvent struct { - id &InitEvent - prv [&DataEvent] // should always be one CID - proof &BlockchainTimestamp - path String -} -``` - -#### Streamid +In order to deactivate a 3ID all capabilities will need to be revoked including the capability with referenced by ``. -Generating the Ceramic streamid can be done in three steps, - -1. Generate the multidid representation of the 3ID, - - ```solidity - := - ``` - -2. Encode the multidid as an inline CID, - - ```solidity - := - ``` - -3. Encode the Streamid - - ```solidity - := - ``` - -#### Create a `DataEvent` - -New data events - -1. Attain a key with a valid capability chain to the most recent *previous data event(s)* - -2. Create one or more `RevocationEntry` objects and update the `State` from the - - previous data event(s): - - 1. Write the objects to a new array and store them on the `actions` field - 2. Also append them to the `registry` map - -3. Create the `DataEvent` struct, - - 1. Set `id` to the principal (an inline CID containing a multidid encoded 3ID), - 2. Add the capability chain used to the `prf` field - 3. Add the previous events to the `prv` field - 4. Add the updated state to the `data` field - 5. Create a `Varsig` over the `DataEvent` with the key from (1) and add the `sig` field - -#### Validating a `DataEvent` - -The certification of a `DataEvent` can be validated using the following algorithm, - -1. The varsig validates agains the *aud* `Principal` of the referenced CACAO - -2. The multihash of the CACAO CID (caphash) is one of: - - 1. CapHash is in the `Registry` and `isRevoked` is false - 2. CapHash is in the `Principal` and **not** in the `Registry` - -3. The CACAO *ability* is one or both of: - - 1. `"3id/add"` - the `Registry` is only allowed to grow and, new values must have `isRevoked = false` -2. `"3id/remove"` - the `Registry` can either grow or stay the same size, all modified values must have `isRevoked = true` - -#### Consensus - -In case of two conflicting events (two events share the same `prv` value) the event with the earliest `TimestampEvent` should be processed first. Note that this might lead to the latter event being invalid due to its delegation chain being revoked. Also, a new event emitted after the conflict must reference both branches in its `prv` and resolve any conflict of the `Registry`. +### Object Capabilities -If there is no anchor for either event yet, the `DataEvent` with the lowest binary value of its CID will win. Note that if a `TimeEvent` appears this order might change. +The 3 DID method relies heavily on the fact that object-capabilities can be used to delegate permissions. It further relies on the `*` permission when delegating authority to give full control over the DID itself and all resources it control. When combined with a way to revoke and notralize capabilities, such as [CapReg](), 3ID can now add and remove any DID as a controller. Including revoking the `` capability itself, without revoking DIDs that have been delegated to before `` was revoked! -#### Verified timestamps +This way of using an object-capability registry is very similar to how adding and removing verification methods from the DID document works in traditional DID methods. -For convenience, once a `TimeEvent` has been verified the data used to verify it can be stored as a receipt. This is helpful when resolving the registry at a particular point in time using the `?versionTime=` DID URL parameter. +#### Delegating full DID control -```verilog -type EthereumHeader // +In order to delegate full control over the 3ID to another DID the following ReCap should be used: -type TimestampRecipt struct { - unixtime Integer // same as block.Time - event &TimestampEvent - block &EthereumHeader - path String // ipld path in the block to find event.txHash +```json +{ + "att":{ + "did:3:zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ": { + "*": [{}] + } + } } ``` -#### Dereferencing the Registry - -The 3 DID resolver can [dereference](https://wiki.trustoverip.org/display/HOME/DID+URL+Resource+Parameter+Specification) the registry to a [CAR file](https://ipld.io/specs/transport/car/carv1/) which can be independently verified. This is achieved by using the `did:3:?resource=vnd.ipld.car` DID URL. Note that the `versionTime` may be used to resolve an earlier snapshot of the registry. - -### Object Capabilities +#### Delegate with exceptions -The 3 DID method relies heavily on object-capabilities as they way to add and remove verification methods, as well as delegating permissions. The root capability is `did/control`, any verification method with this capability has [independent control](https://www.w3.org/TR/did-core/#independent-control) over the DID. This means that they can take any action on behalf of this DID, `*/*` is thus a equivalent of `did/control`. The `did/vm-add` and `did/vm-remove` are actions that can be taken to update the 3ID stream and thus the DID document. In the future other more specific `did/...` capabilities my be specified to define more granular actions on the DID document. - -``` - ┌─────────────┐ - │ did/control │ - └──▲───▲───▲──┘ - ┌────────────┘ │ └────────┐ -┌─────┴──────┐ ┌───────┴───────┐ ┌──┴──┐ -│ did/vm-add │ │ did/vm-remove │ │ */* │ -└────────────┘ └───────────────┘ └─────┘ -``` - -#### Updating the 3ID stream - -In order to make an update to the 3ID stream, one of the verification methods could delegate the following permission to a session key: +Say you want to give a DID the ability to act as your 3ID, but you don't want this DID to be able to delegate full DID control further, nor revoke any capabilities. Then you can add an exclusion to the delegation. ```json { "att":{ "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { - "did/vm-add": [], - "did/vm-remove": [] + "*": [{ "exlude": "crg/*" }] } - // CID of the event to append to the 3ID stream - }, - "prf": [ - { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } - // The CID of the capability that grants the key control over the 3ID - // From this the 3ID can be found, resolve revreg to see if self cap is revoked - ] + } } ``` #### Using a 3ID in Ceramic -In order to act on behalf of a 3ID that controls a Ceramic stream, a delegation can be created by one of the verification methods in the 3ID. Note that the `prf` field must contain a link to the capability for the verification method. +In order to act on behalf of a 3ID that controls a Ceramic stream, a delegation can be created by the `address` that created the 3ID. Or if a delegation to another DID has been created as described above, the delegatee can create a re-delegation. As long as there's a valid delegation chain back to the capability identified by ``, the ReCap delegation described below will be valid for the 3ID. ```json { @@ -378,11 +179,7 @@ In order to act on behalf of a 3ID that controls a Ceramic stream, a delegation "crud/mutate": [], "crud/read": [] } - }, - "prf": [ - { "/": "bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa" } - // The CID of the capability that grants the key control over the 3ID - ] + } } ``` @@ -441,13 +238,15 @@ The capabilityHash verification method type indicates that the verification meth * [CAIP-74: CACAO - Chain Agnostic CApability Object](https://chainagnostic.org/CAIPs/caip-74) -### Stream type code +### Multidid code -**Code:** `5` +**Code:** `0x12` - sha2-256 -### Multidid code +## Appendix B: Multidid encoding + +TODO - clean up! -**Code:** `0x1b` - keccak-256 +In order to encode a 3 DID to multidid format. Simply use the `0x12` code as the identifier and the following data in the identifier as the identifier data. ## Copyright From e72f7f8b678ace434d9dde960c91d7e834ef7b88 Mon Sep 17 00:00:00 2001 From: Joel Thorstensson Date: Thu, 13 Apr 2023 15:49:02 +0200 Subject: [PATCH 4/6] Edits --- CIPs/CIP-122.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/CIPs/CIP-122.md b/CIPs/CIP-122.md index 4e99ec3..a178072 100644 --- a/CIPs/CIP-122.md +++ b/CIPs/CIP-122.md @@ -187,7 +187,7 @@ In order to act on behalf of a 3ID that controls a Ceramic stream, a delegation -While most DID methods include full public keys, or other DIDs as verification methods 3ID chooses to use hashes of object-capabilities as verification methods. One of the main use cases for 3ID is to connect multiple PKH DIDs into a single identifier on Ceramic. While doing so publically is fine for some use cases, the ability to do so privately is quite important for many. Using *capability hashes* enables more privacy since the DIDs that are delegated to doesn't strictly need to be revealed. It is worth noting that revealing the CACAO object when used is the simplest way to prove a capability chain. However, it is possible to create zero-knowledge proofs that only reveal the hash of the capability used and which session key was delegated to. +While most DID methods include full public keys, or other DIDs as verification methods 3ID chooses to use hash of an object-capability as its verification method. One of the main use cases for 3ID is to connect multiple PKH DIDs into a single identifier on Ceramic using object-capability chains. While doing so publically is fine for some use cases, the ability to do so privately is quite important for many. Using a *capability hash* enables more privacy since the DIDs that are delegated to doesn't strictly need to be revealed. It is worth noting that revealing the CACAO object when used is the simplest way to prove a capability chain. However, it is possible to create zero-knowledge proofs that only reveal the hash of the capability used and which session key was delegated to. ### Cryptographic Agility @@ -203,7 +203,7 @@ Once good post quantum cryptography becomes more widely available extending Cera ## Backwards Compatibility -Previous iterations of 3ID relied on the TileDocument stream type and an interpretation layer above that translated the tile contents to a DID document. That approach had numerious flaws the main one being the impossibility of privacy. This version of the spec deviates from the previous experiment in that there is a special stream type for the 3ID and that it fully relies on object-capabilities as verification methods. This is a great improvement but unfortunately it is not possible to make an upgrade in a backwards compatible manner. Instead all implementers are recommended to follow this specification only. +Previous iterations of 3ID relied on the TileDocument stream type and an interpretation layer above that translated the tile contents to a DID document. That approach had numerious flaws the main one being the impossibility of privacy. This version of the spec deviates from the previous version in that it fully relies on object-capabilities and the existance of [CapReg](), while the DID itself remains purely generative. This is a great improvement but unfortunately it is not possible to make an upgrade in a backwards compatible manner. Instead all implementers are recommended to follow this specification only. ## Privacy Requirements @@ -244,9 +244,20 @@ The capabilityHash verification method type indicates that the verification meth ## Appendix B: Multidid encoding -TODO - clean up! +``` + +``` + +Where: + +- `multidid-code` - a varint encoding of `0x0d1d` +- `method-code` - a varint encoding of `0x12` +- `id-lenght` - varint representing the length of the id hash +- `hash-bytes` - MUST contain exactly the number of bytes specified byte the method code +- `url-length` - a varint describing the length of the `url-bytes` parameter +- `url-bytes` - a UTF-8 encoded string representing the [DID URL parameters](https://www.w3.org/TR/did-core/#did-url-syntax) -In order to encode a 3 DID to multidid format. Simply use the `0x12` code as the identifier and the following data in the identifier as the identifier data. +Given a 3 DID `` byte string it's trivial to encode a multidid by simply prepending it with `varint(0x0d1d)`, and appending the url component. ## Copyright From c5c279fc3fe9934f80549b6c94295cacc477c404 Mon Sep 17 00:00:00 2001 From: Joel Thorstensson Date: Thu, 13 Apr 2023 15:56:07 +0200 Subject: [PATCH 5/6] Fix example --- CIPs/CIP-122.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIPs/CIP-122.md b/CIPs/CIP-122.md index a178072..24741cb 100644 --- a/CIPs/CIP-122.md +++ b/CIPs/CIP-122.md @@ -161,7 +161,7 @@ Say you want to give a DID the ability to act as your 3ID, but you don't want th ```json { "att":{ - "did:3:z9CEZ1N1gbFK8J3rxVw3o6M5wygjoNFRSaEtkoGZw5fmbj": { + "did:3:zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ": { "*": [{ "exlude": "crg/*" }] } } From ac9faf8c14236728b78d5d8917427c5d43844b28 Mon Sep 17 00:00:00 2001 From: Joel Thorstensson Date: Wed, 26 Apr 2023 15:21:27 +0200 Subject: [PATCH 6/6] Fix exclude statement --- CIPs/CIP-122.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIPs/CIP-122.md b/CIPs/CIP-122.md index 24741cb..9e9d9fd 100644 --- a/CIPs/CIP-122.md +++ b/CIPs/CIP-122.md @@ -162,7 +162,7 @@ Say you want to give a DID the ability to act as your 3ID, but you don't want th { "att":{ "did:3:zQmWSW4kkZK2MTphhTLFb524ReZxaUjmdHo4uFiNKutAoQJ": { - "*": [{ "exlude": "crg/*" }] + "*": [{ "exlude": "ceramic:/" }] } } }