npm package: @sidetree/element
Description: This package contains an implementation of Sidetree Core, using Ethereum and IPFS
Author: Orie Steele
Latest version: 0.3.1-unstable.60

# @sidetree/element

This package contains an implementation of Sidetree Core, using Ethereum and IPFS

## Run Tests

This package provides a series of tests, which act as a reference for the functionality for Element.
The tests can be run by cloning this repository with the following commands.

```
$ git clone https://github.com/transmute-industries/sidetree.js.git
$ cd sidetree.js/packages/did-method-element
$ npm install
$ npm run test
```

## Set Up a Node

Instructions for setting up an Element node are defined in the following documents.

- [Install Local Development with Ganache](docs/local-dev.md)
- [Install Testnet Development with Ropsten](docs/local-element-ropsten-install.md)
- [Docker Testnet Development with Ropsten](docs/docker-element-ropsten-install.md)

## As a Library

This package is published to NPM and can be included in your own projects with

```
npm install @sidetree/element --save
```

## Element DID Method Specification

Element is an implementation of the Sidetree Protocol that uses the Ethereum blockchain as the ledger layer and IPFS as the content-addressable storage layer
For more information, see [the sidetree spec](https://identity.foundation/sidetree/spec/)

## Method syntax

The namestring identifying this did method is `elem`
A DID that uses this method MUST begin with the following prefix: `did:elem`. Per the DID specification, this string MUST be in lowercase.

An additional optional network specific identifier may be added as such

- `did:elem:ropsten:EiBOWH8368BI9NSaVZTmtxuqwpfN9NwAwy4Z95_VCl6A9g`
- `did:elem:mainnet:EiBOWH8368BI9NSaVZTmtxuqwpfN9NwAwy4Z95_VCl6A9g`
- `did:elem:EiBOWH8368BI9NSaVZTmtxuqwpfN9NwAwy4Z95_VCl6A9g`

By default, if the network specific identifier is not present, then the default is `mainnet`.
The remainder of a DID after the prefix, called the did unique suffix, MUST be a `SHA256` hash of the encoded create payload (see below)

## Parameters

Element follows the default parameters defined in the [Sidetree Protocol Specificaltion](https://identity.foundation/sidetree/spec/#default-parameters).

| Element Parameter               | Element Default                                                                   |
| ------------------------------- | --------------------------------------------------------------------------------- |
| HASH_ALGORITHM                  | SHA256                                                                            |
| HASH_PROTOCOL                   | [Multihash](https://multiformats.io/multihash/)                                   |
| DATA_ENCODING_SCHEME            | Base64URL                                                                         |
| JSON_CANONICALIZATION_SCHEME    | [JCS](https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-17) |
| KEY_ALGORITHM                   | secp256k1                                                                         |
| SIGNATURE_ALGORITHM             | ES256K                                                                            |
| CAS_PROTOCOL                    | [IPFS](https://github.com/ipfs/specs)                                             |
| CAS_URI_ALGORITHM               | IPFS CID                                                                          |
| COMPRESSION_ALGORITHM           | GZIP                                                                              |
| REVEAL_VALUE                    | SHA256 Multihash (0x12)                                                           |
| GENESIS_TIME                    | Smart Contract*                                                                   |
| MAX_CORE_INDEX_FILE_SIZE        | 1 MB (zipped)                                                                     |
| MAX_PROVISIONAL_INDEX_FILE_SIZE | 1 MB (zipped)                                                                     |
| MAX_PROOF_FILE_SIZE             | 2.5 MB (zipped)                                                                   |
| MAX_CHUNK_FILE_SIZE             | 10 MB                                                                             |
| MAX_MEMORY_DECOMPRESSION_FACTOR | 3x file size                                                                      |
| MAX_CAS_URI_LENGTH              | 100 bytes                                                                         |
| MAX_DELTA_SIZE                  | 1,000 bytes                                                                       |
| MAX_OPERATION_COUNT             | 10,000 ops                                                                        |
| MAX_OPERATION_HASH_LENGTH       | 100 bytes                                                                         |
| NONCE_SIZE                      | 16 bytes                                                                          |

Element uses Ethereum for the ledger layer, which means that did's are anchored to the block chain with a smart contract,
instead of being appended to a `NO_OP` transaction. Element will monitor a specific smart contract address for existing 
and new anchor transactions. 

**Ropsten**  
Contract Address: [0x920b7DEeD5CdE055260cdDBD70C000Bbd5b30997](https://ropsten.etherscan.io/address/0x920b7DEeD5CdE055260cdDBD70C000Bbd5b30997)  
Starting Block: [11759377](https://ropsten.etherscan.io/block/11759377)   

## CRUD Operations

Element supports the 4 CRUD operations defined in the [Sidetree Protocol API Specification](https://identity.foundation/sidetree/api/).
Each operation is performed by submitting a Sidetree operation in the form of and HTTP POST request to a Sidetree node.
The body of the HTTP POST request for an operation will have the Content-Type of `application/json` to the `[server path]/operations` REST end point.

```
{
  "type": OPERATION_TYPE,
  ...
}
```

The only required field of the JSON HTTP POST data is the operation type, which can be `create`, `update`, `recover` or `deactivate`.
The other fields are operation specific, and defined in the sections below. Example code for generating each one of these operations
for Element can be found in the [wallet test](https://github.com/transmute-industries/sidetree.js/blob/main/packages/did-method/src/__tests__/wallet.sanity.test.ts).

### Create Operation

Example Create

```json
{
  "type":"create",
  "suffixData":{
    "deltaHash":"EiCP8MJ9oX2jmTxVi6xa1WoGmzkg8HaxmWWiR6R34cUmvw",
    "recoveryCommitment":"EiCFei9R_74JeKbxGIZPI4XXwbb0eDpBeweA9IpymBEOFA"
  },
  "delta":{
    "updateCommitment":"EiDDJ-s9CPjkh6yaH5apLIKZ1G87K0phukB3Fofy2ujeAg",
    "patches":[
      {
        "action":"replace",
        "document":{
          "publicKeys":[
            {
              "id":"signingKey",
              "type":"EcdsaSecp256k1VerificationKey2019",
              "publicKeyJwk":{
                "kty":"EC",
                "crv":"secp256k1",
                "x":"8a7JVJUDcR_mS6gyTAgdvGFZkhO8plwWfId3xqHa7xA",
                "y":"xIxXstl9XR-hXXBkrhzxrFhJRvab2MLhQDus92S8G2o"
              },
              "purposes":[
                "authentication",
                "assertionMethod",
                "capabilityInvocation",
                "capabilityDelegation",
                "keyAgreement"
              ]
            }
          ],
          "services":[
            {
              "id":"serviceId123",
              "type":"someType",
              "serviceEndpoint":"https://www.url.com"
            }
          ]
        }
      }
    ]
  }
}
```

### Recover

Example Recover

```json
{
  "type":"recover",
  "didSuffix":"EiB_4F3m_qz5tBdRmC7tcMOQJxvKSyICzQ4Uxt8cGTN5Vg",
  "revealValue":"EiBDFxzWmxgVG9SH-PY-9Yz73-6mnI8egnypTx1fjlKMKw",
  "signedData":"eyJhbGciOiJFUzI1NksifQ.eyJkZWx0YUhhc2giOiJFaURaeXJBQk13dGZ1YmNGSXlZelhkb09wNXdObzZCNW82MGxvaUg1Qkh3VldRIiwicmVjb3ZlcnlLZXkiOnsia3R5IjoiRUMiLCJjcnYiOiJzZWNwMjU2azEiLCJ4IjoiODZzeDZ5dVdZWjVMRFp1WFd4WF9FdEtrbFN1a21jSDdQZUIzNFNrWUVjZyIsInkiOiJzVlR6VGhVejNDRk82N2doWHVIQXV6Q2ZCVWdKa0V3WkZrbzZQM0ZzNnIwIn0sInJlY292ZXJ5Q29tbWl0bWVudCI6IkVpREFUNGxlYm14S3FTOXFyT1ROZ0lOakJ1aHY1VUJWS1h3Y0NQQ0hiellNX1EifQ.w9jDo4hrTVxbA3oA7QH6YOiTSM5y1f697Dj7m4DPg3ShbhjK3KwXmrHEu5lpFXcxAFB47hW0G1rzm7PpNm9bwQ",
  "delta":{
    "patches":[
      {
        "action":"replace",
        "document":{
            "publicKeys":[
            {
              "id":"signingKey",
              "type":"EcdsaSecp256k1VerificationKey2019",
              "publicKeyJwk":{
                "kty":"EC",
                "crv":"secp256k1",
                "x":"naoGdqBTAvOAVaXjRJb_MW2BPw86iGWLs4i9ylN0dbE",
                "y":"dOfZc0yVkTm70h_ixQOu-B_T29dzxGTILf1-xoqYeao"
              },
              "purposes":[
                "authentication",
                "assertionMethod",
                "capabilityInvocation",
                "capabilityDelegation",
                "keyAgreement"
              ]
            }
          ]
        }
      }
    ],
    "updateCommitment":"EiDDJ-s9CPjkh6yaH5apLIKZ1G87K0phukB3Fofy2ujeAg"
  }
}
```

### Update

Example Update 

```json
{
  "type":"update",
  "didSuffix":"EiBuuicWVxOcbhCW0N9YSRJwB7auqbzhMhKg1qXRTR30_A",
  "revealValue":"EiD0FtXueh5RDV_DlLcOuxjPnT-pheGPfhvaYUivLpGmZA",
  "delta":{
    "patches":[
      {
        "action":"add-services",
        "services":[
          {
            "id":"someId",
            "type":"someType",
            "serviceEndpoint":"someEndpoint"
          }
        ]
      }
    ],
    "updateCommitment":"EiDJa1d1800h2jcvLOJ5eoga5PrIA9WAwxrKGvUYXJwTeQ"
  },
  "signedData":"eyJhbGciOiJFUzI1NksifQ.eyJ1cGRhdGVLZXkiOnsia3R5IjoiRUMiLCJjcnYiOiJzZWNwMjU2azEiLCJ4IjoiMTdOVnAwX3pwLUJON3FkeTJhbkNqcDk1TS1sVF9pZ2xpTENEZ1hvS2F6YyIsInkiOiJ4TzJPQlZSOGxFTW94N1hvYzVYU1dYSC1yUm5jbHk5b2NvTVBUVkhVZmtzIn0sImRlbHRhSGFzaCI6IkVpQ2VkUlZYWGRaU0VMSmRqNzhJclVwaFVJYkVSWFA1UWlrSTN1ZEVvSmFRcEEifQ.-oeeFd4XrAf1L9pt0V_MjXIEubqAEHKPGA1s3JnrdWLHcG3uXF2wZSI_xoDMTlRuwHkJjt-tt918Ce9OXwi4PQ"
}
```

The list of patches currently supported is:

- `add-public-keys`
- `add-authentication`
- `remove-authentication`
- `add-assertion-method`
- `remove-assertion-method`
- `add-capability-delegation`
- `remove-capability-delegation`
- `add-capability-invocation`
- `remove-capability-invocation`
- `add-key-agreement`
- `remove-key-agreement`
- `add-service-endpoint`
- `remove-service-endpoint`


### Deactivate

Example Deactivate.

```json
{
  "type":"deactivate",
  "didSuffix":"EiBuuicWVxOcbhCW0N9YSRJwB7auqbzhMhKg1qXRTR30_A",
  "revealValue":"EiCk-d_6aijSJVJ9K00qlfprLUew_TUZqZ4b8dtl_5mpww",
  "signedData":"eyJhbGciOiJFUzI1NksifQ.eyJkaWRTdWZmaXgiOiJFaUJ1dWljV1Z4T2NiaENXME45WVNSSndCN2F1cWJ6aE1oS2cxcVhSVFIzMF9BIiwicmVjb3ZlcnlLZXkiOnsia3R5IjoiRUMiLCJjcnYiOiJzZWNwMjU2azEiLCJ4IjoiLUhWWFJRNVNGTnRoWFk2Mkxya3N2Z2dqdkVlaEF1Sll3bTVkS0ZZSzJ5ZyIsInkiOiJqQVVqYmo5N3I2dDNTY0pvVW1DTjRwejRpdXVpdGVrMEtKSlFaMndHU1g4In19.L9fl_GHr5jseHUckE0dx4ib-YkFiFBx5YgdFJ8_pcNa71JPTbGT2T4_WY7HUsQqBe_F-yzoDd_FozspFC2PqKw"
}
```

## Resolve Operation

To resolve a DID , send a GET request to the `[server path]/identity/{did}` REST end point.
For example, to resolve the DID `did:elem:ropsten:EiCtwD11AV9e1oISQRHnMJsBC3OBdYDmx8xeKeASrKaw6A` we send a GET request to
`https://ropsten.element.transmute.industries/api/1.0/identifiers/did:elem:ropsten:EiCtwD11AV9e1oISQRHnMJsBC3OBdYDmx8xeKeASrKaw6A`.

And we should get the following response. 
```json
{
  "@context": "https://w3id.org/did-resolution/v1",
  "didDocument": {
    "@context": [
      "https://www.w3.org/ns/did/v1",
      "https://w3id.org/security/suites/jws-2020/v1",
      {
        "@vocab": "https://www.w3.org/ns/did#"
      }
    ],
    "id": "did:elem:ropsten:EiCtwD11AV9e1oISQRHnMJsBC3OBdYDmx8xeKeASrKaw6A",
    "verificationMethod": [
      {
        "id": "#zQ3shvfXLUVwKffPochZ1UkSjxQqpgND3Z5DhzTADooqmmypp",
        "controller": "did:elem:ropsten:EiCtwD11AV9e1oISQRHnMJsBC3OBdYDmx8xeKeASrKaw6A",
        "type": "JsonWebKey2020",
        "publicKeyJwk": {
          "kty": "EC",
          "crv": "secp256k1",
          "x": "7hfx9LZXlMBaZ2EurUcXOITSIGLIFQ4YY7pXCbEqntU",
          "y": "B1FId5MlHAuhxsDU9uvPuE2JXKVPP3ohjuR6HUvY6XM"
        }
      }
    ],
    "authentication": [
      "#zQ3shvfXLUVwKffPochZ1UkSjxQqpgND3Z5DhzTADooqmmypp"
    ],
    "assertionMethod": [
      "#zQ3shvfXLUVwKffPochZ1UkSjxQqpgND3Z5DhzTADooqmmypp"
    ],
    "keyAgreement": [
      "#zQ3shvfXLUVwKffPochZ1UkSjxQqpgND3Z5DhzTADooqmmypp"
    ]
  },
  "didDocumentMetadata": {
    "method": {
      "published": true,
      "recoveryCommitment": "EiB2lrE88cmhcepLS-p8wBbxHfZKSvniCKfL0CfZe4i36g",
      "updateCommitment": "EiBch3E26X_PoJ_Io2NS8-Dn6F94hcMAChZ6-AaZ2B_pUQ"
    },
    "canonicalId": "did:elem:ropsten:EiCtwD11AV9e1oISQRHnMJsBC3OBdYDmx8xeKeASrKaw6A"
  }
}
```

## Security and privacy considerations

A Sidetree did document need not contain a `proof` property. Indeed, all operations are authenticated with the `signature` field of the payload sent to the Sidetree node. This signature is generaged using a key specified in the corresponding DID Document.