Skip to content

Commit

Permalink
Merge branch 'release/v1.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
mi-xu committed Aug 19, 2019
2 parents 55e75d7 + 8ba2d24 commit 5a04777
Show file tree
Hide file tree
Showing 9 changed files with 8,777 additions and 8,551 deletions.
4 changes: 0 additions & 4 deletions .babelrc

This file was deleted.

7 changes: 7 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "standard",
"plugins": ["jest"],
"env": {
"jest/globals": true
}
}
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,19 @@ A `DIDAttributeChanged` event for the identity `0xf3beac30c498d9e26865f34fcaa57d
The resolver presents a simple `resolver()` function that returns a ES6 Promise returning the DID document.

```js
import resolve from 'did-resolver'
import registerResolver from 'ethr-did-resolver'
import { Resolver } from 'did-resolver'
import getResolver from 'ethr-did-resolver'

registerResolver()
// You can set a rpc endpoint to be used by the web3 provider
// You can also set an address for your own ethr-did-registry contract
const providerConfig = { rpcUrl: 'https://rinkeby.infura.io/ethr-did', registry: registry.address }

resolve('did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74').then(doc => console.log)
// getResolver will return an object with a key/value pair of { "ethr": resolver } where resolver is a function used by the generic did resolver.
const ethrDidResolver = getResolver(providerConfig)
const didResolver = Resolver(ethrDidResolver)

didResolver.resolve('did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74').then(doc => console.log)

// You can also use ES7 async/await syntax
const doc = await resolve('did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74')
const doc = await didResolver.resolve('did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74')
```
12 changes: 12 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current'
}
}
]
]
}
294 changes: 294 additions & 0 deletions doc/did-method-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
ETHR DID Method Specification
=================

## Author

- uPort Team: <https://www.uport.me/contact>

## Preface

The ethr DID method specification conforms to the requirements specified in
the [DID specification](https://w3c-ccg.github.io/did-spec/), currently published by the
W3C Credentials Community Group. For more information about DIDs and DID method specifications,
please see the [DID Primer](https://github.com/WebOfTrustInfo/rebooting-the-web-of-trust-fall2017/blob/master/topics-and-advance-readings/did-primer.md)

## Abstract
Decentralized Identifiers (DIDs, see [1]) are designed to be compatible with any distributed ledger or network.
In the Ethereum community, a pattern known as ERC1056 (see [2]) utilizes a smart contract for a lightweight
identity management system intended explicitly for off-chain usage.

The described DID method allows any Ethereum smart contract or key pair account to become a valid identity.
An identity needs no registration. In the case that key management or additional
attributes such as "service endpoints" are required, we deployed ERC1056 smart contracts on:

* Mainnet: `0xdca7ef03e98e0dc2b855be647c39abe984fcf21b`
* Ropsten: `0xdca7ef03e98e0dc2b855be647c39abe984fcf21b`
* Rinkeby: `0xdca7ef03e98e0dc2b855be647c39abe984fcf21b`
* Kovan: `0xdca7ef03e98e0dc2b855be647c39abe984fcf21b`

Since each Ethereum transaction must be funded, there is a growing trend of on-chain transactions that are
authenticated via an externally created signature and not by the actual transaction originator. This allows for
3rd party funding services, or for receivers to pay without any fundamental changes to the underlying
Ethereum architecture. These kinds of transactions have to be signed by an actual key pair and thus cannot be used
to represent smart contract based Ethereum accounts. ERC1056 proposes a way of a smart contract or regular key pair
delegating signing for various purposes to externally managed key pairs. This allows a smart contract to be
represented, both on-chain as well as off-chain or in payment channels through temporary or permanent delegates.

For a reference implementation of this DID method specification see [3].

### Identity Ownership
By default, each identity is controlled by itself. Each identity can only be controlled by a single
address at any given time. By default, this is the address of the identity itself. The owner can
replace themselves with any other Ethereum address, including contracts to allow more advanced
models such as multi-signature ownership.

## Target System

The target system is the Ethereum network where the ERC1056 is deployed. This could either be:
- Mainnet
- Ropsten
- Rinkeby
- Kovan
- other EVM-compliant blockchains such as private chains, or consortium chains.

### Advantages
- No transaction fee on identity creation
- Uses Ethereum's built-in account abstraction
- Multi-sig wallet for identity owner
- Decoupling claims data from the underlying identity
- Decoupling Ethereum interaction from the underlying identity
- Flexibility to use key management
- Flexibility to allow third-party funding service to pay the gas fee if needed
- Supports any EVM-compliant blockchain

## JSON-LD Context Definition
Note, this DID method specification uses the `Secp256k1VerificationKey2018`,
`Secp256k1SignatureAuthentication2018` types and an `ethereumAddress` instead of
a `publicKeyHex`.

The definition of the ethr DID JSON-LD context is:

{
"@context":
{
"ethereumAddress": "https://github.com/uport-project/ethr-did-resolver#ethereumAddress",
"Secp256k1VerificationKey2018": "https://github.com/uport-project/ethr-did-resolver#Secp256k1VerificationKey2018",
"Secp256k1SignatureAuthentication2018": "https://github.com/uport-project/ethr-did-resolver#Secp256k1VerificationKey2018",
}
}

## DID Method Name

The namestring that shall identify this DID method is: `ethr`

A DID that uses this method MUST begin with the following prefix: `did:ethr`. Per the DID specification, this string
MUST be in lowercase. The remainder of the DID, after the prefix, is specified below.

## Method Specific Identifier

The method specific identifier is represented as the Hex-encoded Ethereum address
on the target network.

ethr-did = "did:ethr:" ethr-specific-idstring
ethr-specific-idstring = [ ethr-network ":" ] ethr-address
ethr-network = "mainnet" / "ropsten" / "rinkeby" / "kovan"
ethr-address = "0x" 40*HEXDIG

The Ethereum address is case-insensitive.

Note, if no public Ethereum network was specified, it is assumed that the DID is anchored
on the Ethereum mainnet per default. This means the following DIDs will resolve to the same
DID Document:

did:ethr:mainnet:0xb9c5714089478a327f09197987f16f9e5d936e8a
did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a

## CRUD Operation Definitions

### Create (Register)

In order to create a `ethr` DID, an Ethereum address, i.e., key pair, needs to be generated. At this point,
no interaction with the target Ethereum network is required. The registration is implicit as it is impossible to
brute force an Ethereum address, i.e., guessing the private key for a given public key on the Koblitz Curve
(secp256k). The holder of the private key is the entity identified by the DID.

The minimal DID document for a an Ethereum address, e.g., `0xf3beac30c498d9e26865f34fcaa57dbb935b0d74` with no
transactions to the ERC1056 registry looks like this:

{
'@context': 'https://w3id.org/did/v1',
id: 'did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a',
publicKey: [{
id: 'did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a#owner',
type: 'Secp256k1VerificationKey2018',
owner: 'did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a',
ethereumAddress: '0xb9c5714089478a327f09197987f16f9e5d936e8a'}],
authentication: [{
type: 'Secp256k1SignatureAuthentication2018',
publicKey: 'did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a#owner'}]
}

### Read (Resolve)

The DID document is built by using read only functions and contract events on the ERC1056 registry.

Any value from the registry that returns an Ethereum address will be added to the `publicKey` array of the DID
document with type `Secp256k1VerificationKey2018` and an `ethereumAddress` attribute containing the address.

#### Owner Address

Each identity always has an owner address. By default it is the same as the identity address, but check the
read only contract function `identityOwner(address identity)` on the deployed version of the ERC1056 contract.

The identity owner will always have a `publicKey` with the id set as the DID with the fragment `#owner` appended.

An entry is also added to the `authentication` array of the DID document with type `Secp256k1SignatureAuthentication2018`.

#### Enumerating Contract Events to build the DID Document

The ERC1056 contract publishes three types of events for each identity.
- `DIDOwnerChanged`
- `DIDDelegateChanged`
- `DIDAttributeChanged`

If a change has ever been made for an identity the block number is stored in the changed mapping.

The latest event can be efficiently looked up by checking for one of the 3 above events at that exact block.

Each event contains a `previousChange` value which contains the block number of the previous change (if any).

To see all changes in history for an identity use the following pseudo code:

1. Call `changed(address identity)` on the ERC1056 contract.
2. If result is `null` return.
3. Filter for events for all the above types with the contracts address on the specified block.
4. If event has a previous change then go to 3

#### Delegate Keys

Delegate keys are Ethereum addresses that can either be general signing keys or optionally also perform
authentication.

They are also verifiable from Solidity.

A `DIDDelegateChanged` event is published that is used to build a DID document.

event DIDDelegateChanged(
address indexed identity,
bytes32 delegateType,
address delegate,
uint validTo,
uint previousChange
);

The only 2 `delegateTypes` that are currently published in the DID document are:
- `veriKey` which adds a `Secp256k1VerificationKey2018` to the `publicKey` section of the DID document.
- `sigAuth` which adds a `Secp256k1SignatureAuthentication2018` to the `publicKey` section of document. An entry
is also added to the `authentication` section of the DID document.

Note, the `delegateType` is a `bytes32` type for Ethereum gas efficiency reasons and not a `string`. This
restricts us to 32 bytes, which is why we use the short hand versions above.

Only events with a `validTo` in seconds greater or equal to the current time should be included in the DID document.

#### Non-Ethereum Attributes

Non-Ethereum keys, service endpoints etc. can be added using attributes. Attributes only exist on the
blockchain as contract events of type `DIDAttributeChanged` and can thus not be queried from within solidity code.

event DIDAttributeChanged(
address indexed identity,
bytes32 name,
bytes value,
uint validTo,
uint previousChange
);

Note, the name is a `bytes32` type for Ethereum gas efficiency reasons and not a `string`. This restricts us to
32 bytes, which is why we use the short hand attribute versions below.

While any attribute can be stored, for the DID document we currently support adding to each of these sections of
the DID document:
- Public Keys
- Service Endpoints

#### Public Keys

The name of the attribute added to ERC1056 should follow this format:

`did/pub/(Secp256k1|RSA|Ed25519)/(veriKey|sigAuth)/(hex|base64)`

##### Hex encoded Secp256k1 Verification Key

A `DIDAttributeChanged` event for the identity `0xf3beac30c498d9e26865f34fcaa57dbb935b0d74` with the name
`did/pub/Secp256k1/veriKey/hex` and the value of `0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71`
generates a public key entry like the following:

{
id: "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#delegate-1",
type: "Secp256k1VerificationKey2018",
owner: "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74",
publicKeyHex: '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71'
}

##### Base64 encoded Ed25519 Verification Key
A `DIDAttributeChanged` event for the identity `0xf3beac30c498d9e26865f34fcaa57dbb935b0d74` with the name
`did/pub/Ed25519/veriKey/base64` and the value of `0xb97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71`
generates a public key entry like this:

{
id: "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#delegate-1",
type: "Ed25519VerificationKey2018",
owner: "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74",
publicKeyBase64: "uXww3nZ/CEzjCAFo7ikwU7ozsjXXEWoyY9KfFFCTa3E="
}

#### Service Endpoints
The name of the attribute should follow this format:

`did/svc/[ServiceName]`

A `DIDAttributeChanged` event for the identity `0xf3beac30c498d9e26865f34fcaa57dbb935b0d74` with the name
`did/svc/HubService` and value of the URL `https://hubs.uport.me` hex encoded as
`0x68747470733a2f2f687562732e75706f72742e6d65` generates a service endpoint entry like the following:

{
type: "HubService",
serviceEndpoint: "https://hubs.uport.me"
}

### Update

The DID Document may be updated by invoking the relevant smart contract functions as defined by the ERC1056 standard.
This includes changes to the identity owner, adding delegates and adding additional attributes. Please find a
detailed description in the [ERC1056 documentation](https://github.com/ethereum/EIPs/issues/1056).

These functions will trigger the respective Ethereum events which are used to build the DID Document for a given
identity as described in [Enumerating Contract Events to build the DID Document](#Enumerating-Contract-Events-to-build-the-DID-Document).

### Delete (Revoke)

Two cases need to be distinguished:
- In case no changes were written to ERC1056, nothing needs to be done, and the private key which belongs to the
Ethereum address needs to be deleted from the storage medium used to protect the keys, e.g., mobile device.
- In case ERC1056 was utilized, the owner of the smart contract needs to be set to `0x0`. Although, `0x0`is a valid
Ethereum address, this will indicate the identity has no owner which is a common approach for invalidation,
e.g., tokens. Other elements of the DID Document may be revoked explicitly by invoking the relevant smart contract
functions as defined by the ERC1056 standard. This includes the delegates and additional attributes. Please find a
detailed description in the [ERC1056 documentation](https://github.com/ethereum/EIPs/issues/1056). All these functions
will trigger the respective Ethereum events which are used to build the DID Document for a given identity as
described in [Enumerating Contract Events to build the DID Document](#Enumerating-Contract-Events-to-build-the-DID-Document).

## Reference Implementations

The code at [https://github.com/uport-project/ethr-did-resolver]() is intended to present a reference implementation
of this DID method.

References
----------

**[1]** https://w3c-ccg.github.io/did-spec/

**[2]** https://github.com/ethereum/EIPs/issues/1056

**[3]** https://github.com/uport-project/ethr-did-resolver
Loading

0 comments on commit 5a04777

Please sign in to comment.