Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
5 contributors

Users who have contributed to this file

@thehenrytsai @csuwildcat @AronVanAmmers @sylar217 @AlexITC
568 lines (442 sloc) 29.8 KB

Sidetree Protocol Specification

This specification document describes the Sidetree protocol, which can be applied to any decentralized ledger system (e.g. Bitcoin) to create a 'Layer 2' PKI network. Identifiers and PKI metadata in the protocol are expressed via the emerging Decentralized Identifiers standard, and implementations of the protocol can be codified as their own distinct DID Methods. Briefly, a DID Method is a deterministic mechanism for creating unique identifiers and managing metadata (DID Documents) associated with these identifiers, without the need for a centralized authority, denoted by unique prefixes that distinguish one DID Method's identifiers from another (did:foo, did:bar, etc.).

Overview

Using blockchains for anchoring and tracking unique, non-transferable, digital entities is a useful primitive, but the current strategies for doing so suffer from severely limited transactional performance constraints. Sidetree is a layer-2 protocol for anchoring and tracking DID Documents across a blockchain. The central design idea involves batching multiple DID Document operations into a single blockchain transaction. This allows Sidetree to inherit the immutability and verifiability guarantees of blockchain without being limited by its transaction rate.

Sidetree System Overview

Architecturally, a Sidetree network is a network consisting of multiple logical servers (Sidetree nodes) executing Sidetree protocol rules, overlaying a blockchain network as illustrated by the above figure. Each Sidetree node provides service endpoints to perform operations (e.g. Create, Resolve, Update, and Delete) against DID Documents. The blockchain consensus mechanism helps serialize Sidetree operations published by different nodes and provide a consistent view of the state of all DID Documents to all Sidetree nodes, without requiring its own consensus layer. The Sidetree protocol batches multiple operations in a single file (batch file) and stores the batch files in a distributed content-addressable storage (DCAS or CAS). A reference to the operation batch is then anchored on the blockchain. The actual data of all batched operations are stored as one . Anyone can run a CAS node without running a Sidetree node to provide redundancy of Sidetree batch files.

Terminology

Term Description
Anchor file The file containing metadata of a batch of Sidetree operations, of which the hash is written to the blockchain as a Sidetree transaction.
Batch file The file containing all the operation data batched together.
CAS Same as DCAS.
DCAS Distributed content-addressable storage.
DID Document A document containing metadata of a DID, see DID specification.
DID unique suffix The unique portion of a DID. e.g. The unique suffix of 'did:sidetree:abc' would be 'abc'.
Operation A change to a DID Document.
Operation hash The hash of the encoded payload of an operation request.
Operation request A JWS formatted request sent to a Sidetree node to perform an operation.
Original DID Document A DID Document that is used in create operation to generate the DID.
Recovery key A key that is used to perform recovery or delete operation.
Sidetree node A logical server executing Sidetree protocol rules.
Transaction A blockchain transaction representing a batch of Sidetree operations.

Format and Encoding

  • JSON is used as the data encapsulation format.
  • Base64URL encoding is used whenever encoding is needed for binary data or cryptographic consistency.
  • Multihash is used to represent hashes.

Sidetree Protocol Versioning & Parameters

Sidetree protocol and parameters are expected to evolve overtime. Each version of the protocol will define the logical blockchain time in which the new rules and parameter values will take effect. All subsequent transactions will adhere to the same rules and parameter values until a newer protocol version is defined.

The following lists the parameters of each version of the Sidetree protocol.

v1.0

Parameter Value
Starting blockchain time 500000 (bitcoin)
Hash algorithm SHA256
Maximum batch size 10000
Maximum operation size 2 KB

Sidetree Operations

A DID Document is a document containing information about a DID, such as the public keys of the DID owner and service endpoints used. Sidetree protocol enables the creation of, lookup for, and updates to DID Documents through Sidetree operations. All operations are authenticated with a signature using a key specified in the corresponding DID Document.

An update to a DID Document is specified as a JSON patch so that only differences from the previous version of the DID Document is specified in each operation.

NOTE: Create and recover operations require a complete DID Document as input as opposed to a JSON patch.

Sidetree Operation Hashes

An operation hash is the hash of the encoded payload of a Sidetree operation request. The exact request schema for all operations are defined in Sidetree REST API section. With the exception of the create operation, each operation must reference the previous operation using the operation hash, forming a chain of change history.

Sidetree DID and Original DID Document

A Sidetree DID is intentionally the hash of the encoded DID Document given as the create operation payload (original DID Document), prefixed by the Sidetree method name. Given how operation hash is computed, A DID is also the operation hash of the initial create operation.

Since the requester is in control of the original DID Document, the requester can deterministically calculate the DID before the create operation is anchored on the blockchain.

A valid original DID Document must be a valid generic DID Document that adheres to the following additional Sidetree protocol specific rules:

  1. The document must NOT have the id property.
  2. The document must contain at least 1 entry in the publicKey array property.
  3. The id property of a publickey element must be specified and be a fragment (e.g. #key1).
  4. Can have service property.
  5. serviceEndpoint property of each element inside the service array must:
    1. Contain a @context property with value schema.identity.foundation/hub.
    2. Contain a @type property with value UserServiceEndpoint.
    3. Contain at least one element in an instance property typed as an array of strings.

See DID Create API section for an example of an original DID Document.

Sidetree Operation Batching

The Sidetree protocol increases operation throughput by batching multiple operations together then anchoring a reference to this batch on the blockchain. For every batch of Sidetree operations created, there are two files that are created and stored in the CAS layer:

  1. Batch file - The file containing the actual change data of all the operations batched together.

  2. Anchor file - The hash of the anchor file is written to the blockchain as a Sidetree transaction, hence the name 'anchor'. This file contains the following:

    1. Metadata about the associated Sidetree operations, including a content addressable hash of the operation batch file.
    2. Array of DID suffixes (the unique portion of the DID string that differentiates one DID from another) for all DIDs that are declared to have operations within the associated batch file.
    3. The Merkle Root of the tree constructed from all the operations in the batch file, to aid in proving an operation was included in a given transaction with minimal overhead.

Batch File Schema

The batch file is a ZIP compressed JSON document of the following schema:

{
  "operations": [
    "Encoded operation",
    "Encoded operation",
    ...
  ]
}

Anchor File Schema

The anchor file is a JSON document of the following schema:

{
  "batchFileHash": "Encoded hash of the batch file.",
  "didUniqueSuffixes": ["Unique suffix of DID of 1st operation", "Unique suffix of DID of 2nd operation", "..."],
  "merkleRoot": "Encoded root hash of the Merkle tree constructed from the operations included in the batch file."
}

NOTE: See Sidetree Operation Receipts section on purpose and construction of the merkleRoot.

Operation chaining of a DID

DID Operation Chaining

Batch Scaling & DDoS Mitigation

Given the protocol was designed to enable operations to be performed at large volumes with cheap unit costs, DDoS is a real threat to the system.

Without any mitigation strategy, each Sidetree batch can be arbitrarily large, allowing malicious, but protocol adherent nodes to create and broadcast massive operation batches that are not intended for any other purpose than to force other observing nodes to process their operations in accordance with the protocol.

Sidetree protocol defines the following two mechanisms to enable scaling, while preventing DDoS attacks:

Maximum batch size

By defining a maximum number of operations per batch, the strategy circumvents participants to anchor arbitrarily large trees on the system. At its core, this mitigation strategy forces the attacker to deal with the organic economic pressure exerted by the underlying chain's transactional unit cost. Each instantiation of a Sidetree-based DID Method may select a different maximum batch size; the size for the default configuration is TBD.

Proof of Fee

Each Sidetree transaction on the target chain is required to include a deterministic, protocol-specified fee, based on the number of DID operations they seek to include via the on-chain transaction. The deterministic protocol rules for the default configuration are still under discussion, but the following are roughly represent the direction under discussion:

  1. Simple inclusion of a transaction in a block will enable the transaction writer to include a baseline of N operations
  2. Any number of operations that exceed N will be subject to proof that a fee was paid that meets or exceeds a required amount, determined as follows:
    1. Let the block range R include the last block the node believes to be the latest confirmed and the 9 blocks that precede it.
    2. Compute an array of median fees M, wherein the result of each computation is the median of all transactions fees in each block, less any Sidetree-bearing transactions.
    3. Let the target fee F be the average of all the values contained in M.
    4. Let the per operation cost C be F divided by the baseline amount N.
  3. To test the batch for adherence to the Proof of Fee requirement, divide the number of operations in the batch by the fee paid in the host transaction, and ensure that the resulting per operation amount exceeds the required per operation cost C.

Sidetree Transaction Processing

A Sidetree transaction represents a batch of operations to be processed by Sidetree nodes. Each transaction is assigned a monotonically increasing number (but need not be increasing by one), the transaction number deterministically defines the order of transactions, and thus the order of operations. A transaction number is assigned to all Sidetree transactions irrespective of their validity, however a transaction must be valid before individual operations within it can be processed. An invalid transaction is simply discarded by Sidetree nodes. The following rules must be followed for determining the validity of a transaction:

  1. The corresponding anchor file must strictly follow the schema defined by the protocol. An anchor file with missing or additional properties is invalid.

  2. The corresponding batch file must strictly follow the schema defined by the protocol. A batch file with missing or additional properties is invalid.

  3. The operation batch size must not exceed the maximum size specified by the protocol.

  4. The transaction must meet the proof-of-fee requirements defined by the protocol.

  5. Every operation batched in the same transaction must adhere to the following requirements to be considered a well-formed operation, one not-well-formed operation in the batch file renders the entire transaction invalid:

    1. Follow the operation schema defined by the protocol, it must not have missing or additional properties.

    2. Must not exceed the operation size specified by the protocol.

    3. Must use the hashing algorithm specified by the protocol.

NOTE: A transaction is not considered to be invalid if the corresponding anchor file or batch file cannot be found. Such transactions are unresolvable transactions, and must be reprocessed when the its anchor file and batch file become available.

DID Deletion and Recovery

Sidetree protocol requires the specification by the DID owner of dedicated cryptographic keys, called recovery keys, for deleting or recovering a DID. At least one recovery key is required to be specified in every Create and Recover operation. Recovery keys can only be changed by another recovery operation. Once a DID is deleted, it cannot be recovered.

The most basic recovery operation, most often used to regain control after loss or theft of a controlling device/key, is one coded as a specific recovery activity and invokes a designated recovery key to sign the operation. The operation is processes by observing nodes as an override that supercedes all other key types present in the current DID Document.

Sidetree REST API

A Sidetree node exposes a set of REST API that enables the creation of new DIDs and their initial state, subsequent DID Document updates, and DID Document resolutions. This section defines the v1.0 version of the Sidetree REST API.

Response HTTP status codes

HTTP status code Description
200 Everything went well.
401 Unauthenticated or unauthorized request.
400 Bad client request.
500 Server error.

JSON Web Signature (JWS)

Every operation request sent to a Sidetree node must be signed using the flattened JWS JSON serialization scheme.

When constructing the JWS input for signing (JWS Signing Input), the following scheme is specified by the JWS specification:

ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload))

Since there is no protected header in a Sidetree operation, the JWS Signing Input will always begin with the '.' character.

Note that signature validation is only being performed when the Sidetree node is processing operations anchored on the blockchain. No signature validation will be done when the operation requests are being received and handled. This is because there is no way of guaranteeing/enforcing the validity of the signing key used in an update since the signing key could have been invalidated in an earlier update that has not been anchored or seen by the Sidetree node yet.

DID and DID Document Creation

Use this API to create a Sidetree DID and its initial state.

An encoded original DID Document must be supplied as the request payload, see Original DID Document section for the requirements of a valid original DID Document.

Request path

POST /<api-version>/ HTTP/1.1

Request headers

Name Value
Content-Type application/json

Request body schema

{
  "header": {
    "operation": "create",
    "kid": "ID of the key used to sign the original DID Document.",
    "alg": "ES256K"
  },
  "payload": "Encoded original DID Document.",
  "signature": "Encoded signature."
}

Original DID Document example

{
  "@context": "https://w3id.org/did/v1",
  "publicKey": [{
    "id": "#key1",
    "type": "Secp256k1VerificationKey2018",
    "publicKeyHex": "02f49802fb3e09c6dd43f19aa41293d1e0dad044b68cf81cf7079499edfd0aa9f1"
  }],
  "service": [{
    "id": "IdentityHub",
    "type": "IdentityHub",
    "serviceEndpoint": {
      "@context": "schema.identity.foundation/hub",
      "@type": "UserServiceEndpoint",
      "instance": ["did:bar:456", "did:zaz:789"]
    }
  }]
}

Request example

POST /v1.0/ HTTP/1.1

{
  "header": {
    "operation": "create",
    "kid": "#key1",
    "alg": "ES256K"
  },
  "payload": "eyJAY29udGV4dCI6Imh0dHBzOi8vdzNpZC5vcmcvZGlkL3YxIiwicHVibGljS2V5IjpbeyJpZCI6IiNrZXkxIiwidHlwZSI6IlNlY3AyNTZrMVZlcmlmaWNhdGlvbktleTIwMTgiLCJwdWJsaWNLZXlIZXgiOiIwMmY0OTgwMmZiM2UwOWM2ZGQ0M2YxOWFhNDEyOTNkMWUwZGFkMDQ0YjY4Y2Y4MWNmNzA3OTQ5OWVkZmQwYWE5ZjEifSx7ImlkIjoiI2tleTIiLCJ0eXBlIjoiUnNhVmVyaWZpY2F0aW9uS2V5MjAxOCIsInB1YmxpY0tleVBlbSI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS4yLkVORCBQVUJMSUMgS0VZLS0tLS0ifV0sInNlcnZpY2UiOlt7InR5cGUiOiJJZGVudGl0eUh1YiIsInB1YmxpY0tleSI6IiNrZXkxIiwic2VydmljZUVuZHBvaW50Ijp7IkBjb250ZXh0Ijoic2NoZW1hLmlkZW50aXR5LmZvdW5kYXRpb24vaHViIiwiQHR5cGUiOiJVc2VyU2VydmljZUVuZHBvaW50IiwiaW5zdGFuY2VzIjpbImRpZDpiYXI6NDU2IiwiZGlkOnphejo3ODkiXX19XX0",
  "signature": "mAJp4ZHwY5UMA05OEKvoZreRo0XrYe77s3RLyGKArG85IoBULs4cLDBtdpOToCtSZhPvCC2xOUXMGyGXDmmEHg"
}

Response headers

Name Value
Content-Type application/json

Response body schema

The response body is the constructed DID Document of the DID created.

Response body example

{
  "@context": "https://w3id.org/did/v1",
  "id": "did:sidetree:EiBJz4qd3Lvof3boqBQgzhMDYXWQ_wZs67jGiAhFCiQFjw",
  "publicKey": [{
    "id": "#key1",
    "type": "Secp256k1VerificationKey2018",
    "publicKeyHex": "029a4774d543094deaf342663ae672728e12f03b3b6d9816b0b79995fade0fab23"
  }],
  "service": [{
    "id": "IdentityHub",
    "type": "IdentityHub",
    "serviceEndpoint": {
      "@context": "schema.identity.foundation/hub",
      "@type": "UserServiceEndpoint",
      "instance": ["did:bar:456", "did:zaz:789"]
    }
  }]
}

DID Document resolution

This API fetches the latest DID Document of a DID. Two types of string can be passed in the URI:

  1. DID

    e.g. did:sidetree:exKwW0HjS5y4zBtJ7vYDwglYhtckdO15JDt1j5F5Q0A

    The latest DID Document will be returned if found.

  2. Method name prefixed, encoded original DID Document

    e.g. did:sidetree:ewogICAgICAiQGNvbnRleHQiOiAiaHR0cHM6Ly93M2lkLm9yZy9kaWQvdjEiLAogICAgICAicHVibGljS2V5IjogWwogICAgICAgIHsKICAgICAgICAgICAgImlkIjogIiNrZXkxIiwKICAgICAgICAgICAgInR5cGUiOiAiU2VjcDI1NmsxVmVyaWZpY2F0aW9uS2V5MjAxOCIsCiAgICAgICAgICAgICJwdWJsaWNLZXlIZXgiOiAiMDM0ZWUwZjY3MGZjOTZiYjc1ZThiODljMDY4YTE2NjUwMDdhNDFjOTg1MTNkNmE5MTFiNjEzN2UyZDE2ZjFkMzAwIgogICAgICAgIH0KICAgICAgXQogICAgfQ

    The encoded DID Document is hashed using the current supported hashing algorithm to obtain the corresponding DID, after which the resolution is done against the computed DID. If a DID Document cannot be found, the supplied DID Document is used directly to generate and return a resolved DID Document, in which case the supplied DID Document is subject to the same validation as an original DID Document in a create operation.

Request path

GET /<api-version>/<did-or-method-name-prefixed-encoded-original-did-document> HTTP/1.1

Request headers

None.

Request body schema

None.

Request example - DID

GET /v1.0/did:sidetree:exKwW0HjS5y4zBtJ7vYDwglYhtckdO15JDt1j5F5Q0A HTTP/1.1

Request example - Method name prefixed, encoded original DID Document

GET /v1.0/did:sidetree:ewogICAgICAiQGNvbnRleHQiOiAiaHR0cHM6Ly93M2lkLm9yZy9kaWQvdjEiLAogICAgICAicHVibGljS2V5IjogWwogICAgICAgIHsKICAgICAgICAgICAgImlkIjogIiNrZXkxIiwKICAgICAgICAgICAgInR5cGUiOiAiU2VjcDI1NmsxVmVyaWZpY2F0aW9uS2V5MjAxOCIsCiAgICAgICAgICAgICJwdWJsaWNLZXlIZXgiOiAiMDM0ZWUwZjY3MGZjOTZiYjc1ZThiODljMDY4YTE2NjUwMDdhNDFjOTg1MTNkNmE5MTFiNjEzN2UyZDE2ZjFkMzAwIgogICAgICAgIH0KICAgICAgXQogICAgfQ HTTP/1.1

Response body schema

The response body is the latest DID Document.

Response body example

{
  "@context": "https://w3id.org/did/v1",
  "id": "did:sidetree:EiBJz4qd3Lvof3boqBQgzhMDYXWQ_wZs67jGiAhFCiQFjw",
  "publicKey": [{
    "id": "#key1",
    "type": "Secp256k1VerificationKey2018",
    "publicKeyHex": "029a4774d543094deaf342663ae672728e12f03b3b6d9816b0b79995fade0fab23"
  }],
  "service": [{
    "id": "IdentityHub",
    "type": "IdentityHub",
    "serviceEndpoint": {
      "@context": "schema.identity.foundation/hub",
      "@type": "UserServiceEndpoint",
      "instance": ["did:bar:456", "did:zaz:789"]
    }
  }]
}

Updating a DID Document

The API to update a DID Document.

Request path

POST /<api-version>/ HTTP/1.1

Request headers

Name Value
Content-Type application/json

Request body schema

{
  "header": {
    "operation": "update",
    "kid": "ID of the key used to sign the update payload.",
    "alg": "ES256K"
  },
  "payload": "Encoded update payload JSON object define by the schema below.",
  "signature": "Encoded signature."
}

Update payload schema

{
  "didUniqueSuffix": "The unique suffix of the DID",
  "operationNumber": "The number incremented from the last change version number. 1 if first change.",
  "previousOperationHash": "The hash of the previous operation made to the DID Document.",
  "patch": "An RFC 6902 JSON patch to the current DID Document",
}

Update payload schema example

{
  "didUniqueSuffix": "QmWd5PH6vyRH5kMdzZRPBnf952dbR4av3Bd7B2wBqMaAcf",
  "operationNumber": 12,
  "previousOperationHash": "QmbJGU4wNti6vNMGMosXaHbeMHGu9PkAUZtVBb2s2Vyq5d",
  "patch": [{
    "op": "remove",
    "path": "/publicKey/0"
  }]
}

Request example

POST /v1.0/ HTTP/1.1

{
  "header": {
    "operation": "update",
    "kid": "#key1",
    "alg": "ES256K"
  },
  "payload": "eyJkaWQiOiJkaWQ6c2lkZXRyZWU6RWlERkRGVVNnb3hsWm94U2x1LTE3eXpfRm1NQ0l4NGhwU2FyZUNFN0lSWnYwQSIsIm9wZXJhdGlvbk51bWJlciI6MSwicHJldmlvdXNPcGVyYXRpb25IYXNoIjoiRWlERkRGVVNnb3hsWm94U2x1LTE3eXpfRm1NQ0l4NGhwU2FyZUNFN0lSWnYwQSIsInBhdGNoIjpbeyJvcCI6InJlcGxhY2UiLCJwYXRoIjoiL3B1YmxpY0tleS8xIiwidmFsdWUiOnsiaWQiOiIja2V5MiIsInR5cGUiOiJTZWNwMjU2azFWZXJpZmljYXRpb25LZXkyMDE4IiwicHVibGljS2V5SGV4IjoiMDI5YTQ3NzRkNTQzMDk0ZGVhZjM0MjY2M2FlNjcyNzI4ZTEyZjAzYjNiNmQ5ODE2YjBiNzk5OTVmYWRlMGZhYjIzIn19XX0",
  "signature": "nymBtWB1_nwtSdrHsb2uiIa91yTJWN-lqANEcspjp-9kd079jlGWoYIxgvVKJkW-WJkYA5Kryws9G5XIfup5RA"
}

Response body

None.

DID Deletion

The API to delete a given DID.

Request path

POST /<api-version>/

Request headers

Name Value
Content-Type application/json

Request body schema

{
  "header": {
    "operation": "delete",
    "kid": "ID of the key used to sign the delete payload.",
    "alg": "ES256K"
  },
  "payload": "Encoded update payload JSON object define by the schema below.",
  "signature": "Encoded signature."
}

Delete payload schema

{
  "didUniqueSuffix": "The unique suffix of the DID to be deleted.",
}

Delete payload example

{
  "didUniqueSuffix": "QmWd5PH6vyRH5kMdzZRPBnf952dbR4av3Bd7B2wBqMaAcf",
}

Request example

POST /v1.0/ HTTP/1.1
{
  "header": {
    "operation": "delete",
    "kid": "#key1",
    "alg": "ES256K"
  },
  "payload": "3hAPKZnaKcJkR85UvXhiAH7majrfpZGFFVJj8tgAtK9aSrxnrbygDTN2URoQEghPbWtFgZDMNU6RQjiMD1dpbEaoZwKBSVB3oCq1LR2",
  "signature": "nymBtWB1_nwtSdrHsb2uiIa91yTJWN-lqANEcspjp-9kd079jlGWoYIxgvVKJkW-WJkYA5Kryws9G5XIfup5RA"
}

Response body

None.

DID Recovery

TODO: API to be added which will impact delete API also.

Merkle Root Hash Inclusion

Sidetree anchor file also includes the root hash of a Merkle tree constructed using the hashes of batched operations.

The main protocol does not rely on the root hash to operate and the usefulness of the Merkle root is still being discussed, but since this hash is small, stored off-chain, and cheap to compute and store, we do. There is an opportunity for an API or service to return a concise receipt (proof) for a given operation such that this operation can be cryptographically proven to be part of a batch without the need of the entire batch file. Note this receipt cannot be provided in the response of the operation request because Merkle tree construction happens asynchronously when the final batch is formed.

Specifically, Sidetree uses an unbalanced Merkle tree construction to handle the (most common) case where the number of operations in a batch is not mathematically a power of 2: a series of uniquely sized balanced Merkle trees is formed where operations with lower index in the list of operations form larger trees; then the smallest balanced subtree is merged with the next-sized balanced subtree recursively to form the final Merkle tree.

Sidetree Operation Batching Examples

The following illustrates the construction of the Merkle tree with an array of 6 operations:

  • The smallest balance subtree I of 2 leaves [4, 5] is merged with the adjacent balanced tree J of 4 leaves [0, 1, 2, 3] to form the final Merkle tree.
  • Receipt for [0] will be [B, H, I], and receipt for [5] will be [E, J].
                          ROOT=H(J+I)
                          /          \
                        /              \
                J=H(G+H)                 \
              /        \                   \
            /            \                   \
      G=H(A+B)             H=H(C+D)          I=H(E+F)
      /      \             /     \           /      \
    /        \           /        \         /        \
  A=H([0])  B=H([1])  C=H([2])  D=H([3])  E=H([4])  F=H([5])
    |         |         |         |         |         |
    |         |         |         |         |         |
[   0    ,    1    ,    2    ,    3    ,    4    ,    5   ]

Where: [1] -> Denotes the binary buffer of the 1st element in the array of operation data.
        |  -> Denotes the logical relationship between an operation data and its hash.
       H() -> Denotes a hash function that returns a binary buffer representing the hash.
       A+B -> Denotes the concatenation of two binary buffers A and B.

The following illustrates the construction of the Merkle tree with an array of 7 operations:

  • The smallest balanced subtree G of 1 leaf [6] is merged with the adjacent balanced subtree J of 2 leaves [4, 5] to form parent L, which in turn is merged with the adjacent balanced subtree K of 4 leaves [0, 1, 2, 3] to form the final Merkle tree.
  • Receipt for [0] will be [B, I, L]; receipt for [4] will be [F, G, K]; receipt for [6] will be [J, K].
                             ROOT=H(K+L)
                          /               \
                        /                  \
                K=H(H+I)                    L=H(J+G)
              /        \                     /       \
            /            \                  /          \
      H=H(A+B)             I=H(C+D)        J=H(E+F)      \
      /      \             /     \         /      \        \
     /        \           /       \       /         \        \
  A=H([0])  B=H([1])  C=H([2])  D=H([3])  E=H([4])  F=H([5])  G=H([6])
    |         |         |         |         |         |         |
    |         |         |         |         |         |         |
[   0    ,    1    ,    2    ,    3    ,    4    ,    5    ,    6   ]

Operation Receipts

While currently unused, Sidetree proposes the following JSON schema to represent a receipt:

{
  "receipt": [
    {
      "hash": "A Merkle tree node hash.",
      "side": "Must be 'left' or 'right', denotes the position of this hash."
    },
    ...
  ]
}

Where the first entry in receipt is the sibling of the operation hash in the Merkle tree; followed by the uncle, then the great uncle and so on.

NOTE: This scheme does not include the root hash as the last entry of the receipt.

NOTE: Receipt array will be empty thus is optional if no batching occurs (i.e. a tree of one operation).

FAQs

  • Why introduce the concept of an anchor file? Why not just anchor the batch file hash directly on blockchain?

    It would be ideal to be able to fetch metadata about the batched operations efficiently, without needing to download the entire batch file. This design is needed for the implementation of "light nodes", it also opens up possibilities of other applications of the Sidetree protocol.

  • Why assign a transaction number to invalid transactions?

    In the case of an unresolvable transaction, it is unknown if the transaction will be valid or not if it becomes resolvable, thus it is assigned a transaction number such that if the transaction turns out to be valid, the transaction number of valid transactions that occur at a later time remain immutable. This also enables all Sidetree nodes to refer to the same transaction using the same transaction number.

You can’t perform that action at this time.