# CIP-79: 3ID DID Method Specification  
| Author | [Joel Thorstensson](https://github.com/oed) |
| Discussions-To | [https://github.com/ceramicnetwork/CIP/issues/80](https://github.com/ceramicnetwork/CIP/issues/80) |
| Status | Draft |
| Category | RFC |
| Created | 2021-02-12 |

## Table of Contents

- [3ID DID Method Specification](https://cips.ceramic.network/CIPs/cip-79#3id-did-method-specification)
  - [DID Method Name](https://cips.ceramic.network/CIPs/cip-79#did-method-name)
  - [Method Specific Identifier](https://cips.ceramic.network/CIPs/cip-79#method-specific-identifier)
    - [3IDv1](https://cips.ceramic.network/CIPs/cip-79#3idv1)
    - [3IDv0](https://cips.ceramic.network/CIPs/cip-79#3idv0)
  - [CRUD Operation Definitions](https://cips.ceramic.network/CIPs/cip-79#crud-operation-definitions)
    - [Create](https://cips.ceramic.network/CIPs/cip-79#create)
    - [Read/Verify](https://cips.ceramic.network/CIPs/cip-79#readverify)
    - [Update](https://cips.ceramic.network/CIPs/cip-79#update)
    - [Deactivate](https://cips.ceramic.network/CIPs/cip-79#deactivate)
  - [Security Requirements](https://cips.ceramic.network/CIPs/cip-79#security-requirements)
    - [Cryptographic Agility](https://cips.ceramic.network/CIPs/cip-79#cryptographic-agility)
  - [Privacy Requirements](https://cips.ceramic.network/CIPs/cip-79#privacy-requirements)
  - [Extensibility](https://cips.ceramic.network/CIPs/cip-79#extensibility)
  - [Reference Implementations](https://cips.ceramic.network/CIPs/cip-79#reference-implementations)
  - [Appendix A](https://cips.ceramic.network/CIPs/cip-79#appendix-a)
  - [Copyright](https://cips.ceramic.network/CIPs/cip-79#copyright)

# 3ID DID Method Specification

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

The name string that shall identify this DID method is: `3`.

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

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.

### 3IDv1

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).

```
3idv1 = "did:3:<StreamId>"
```

#### Example

```
did:3:kjzl6cwe1jw149tlplc4bgnpn1v4uwk9rg9jkvijx0u0zmfa97t69dnqibqa2as
```

### 3IDv0

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).

```
3idv0 = "did:3:<cid>"
```

#### Example

```
did:3:bafyreiffkeeq4wq2htejqla2is5ognligi4lvjhwrpqpl2kazjdoecmugi
```

## CRUD Operation Definitions

In this section the CRUD operations for a 3ID DID are defined.

### Create

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`.

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.

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.

#### Example

Below you can see an example of how to create a 3ID using the Ceramic javascript api.

```
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
})

const didString = `did:3:${doc.id}`
```

### Read/Verify

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.

#### Loading 3IDv1 stream

To load a 3IDv1 document simply take the StreamID from the method specific identifier and load the stream from ceramic.

#### Loading 3IDv0 document

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](https://cips.ceramic.network/CIPs/cip-79#appendix-a)).

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.

```
const doc = await ceramic.createDocument({
  metadata: {
    controllers: [didKey], // secp256k1 did:key
    family: '3id'
  },
  deterministic: true
})
```

#### Converting the loaded Ceramic stream to the DID document

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:

```
{
  "publicKeys": {
    "j9uh8iKHSDSLat4": "zQ3shaLgXkpEXt7He5mogBxFfib5cE2kv9j9uh8iKHSDSLat4",
    "qYfZN2QNDgjJpaL": "z6LSnTyV1nSWfMmfV1PoRmo3enhDnfqfFqYfZN2QNDgjJpaL"
  }
}
```

To convert this into a DID document first create an empty DID document:

```
{
  "@context": "https://w3id.org/did/v1",
  "id": "<did>",
  "verificationMethod": [],
  "authentication": [],
  "keyAgreement": []
}
```

Now iterate though the entires in the `publicKeys` object in the Ceramic stream and do the following:

- If it’s a `secp256k1` key:
  - Add a `Secp256k1VerificationKey2018` to the _verificationMethod_ array:
  
```
{
  id: "<did>#<entry-key>",
  type: "EcdsaSecp256k1Signature2019",
  controller: "<did>",
  publicKeyBase58: "<entry-value-public-key-base58btc-encoded>"
}
```

- Add a `Secp256k1SignatureAuthentication2018` to the _authentication_ array:
  
```
{
  id: "<did>#<entry-key>",
  type: "EcdsaSecp256k1Signature2019",
  controller: "<did>",
  publicKeyBase58: "<entry-value-public-key-base58btc-encoded>"
}
```
- If it’s a `x25519` key:
  - Add a `Curve25519EncryptionPublicKey` to the _verificationMethod_ array:
  
```
{
  id: "<did>#<entry-key>",
  type: "X25519KeyAgreementKey2019",
  controller: "<did>",
  publicKeyBase58: "<entry-value-public-key-base58btc-encoded>"
}
```

- Add a `X25519KeyAgreementKey2019` to the _keyAgreement_ array:
  
```
{
  id: "<did>#<entry-key>",
  type: "X25519KeyAgreementKey2019",
  controller: "<did>",
  publicKeyBase58: "<entry-value-public-key-base58btc-encoded>"
}
```

##### 3IDv0 genesis

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](https://cips.ceramic.network/CIPs/cip-79#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.

##### DID Document Metadata

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:

- `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_

#### Resolving using the `versionId` parameter

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.

##### DID Document Metadata

- `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)

### Update

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.

### Deactivate

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`.

## Security Requirements

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).

### Cryptographic Agility

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.

## Privacy Requirements

See [§ 10\. Privacy Considerations](https://www.w3.org/TR/did-core/#privacy-considerations) in `did-core`.

## Extensibility

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.

## Reference Implementations

- [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

## Appendix A

An example 3IDv0 genesis object

```
{
  "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"\
      }\
    ],
    "authentication": [\
      {\
        "type": "Secp256k1SignatureAuthentication2018",\
        "publicKey": "did:3:GENESIS#signingKey"\
      }\
    ]
  }
}
```

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
