eip-1056.md
1 --- 2 eip: 1056 3 title: Ethereum Lightweight Identity 4 author: Pelle Braendgaard <pelle.braendgaard@consensys.net>, Joel Torstensson <oed@consensys.net> 5 type: Standards Track 6 category: ERC 7 discussions-to: https://github.com/ethereum/EIPs/issues/1056 8 status: Draft 9 created: 2018-05-03 10 --- 11 12 ## Simple Summary 13 14 A registry for key and attribute management of lightweight blockchain identities. 15 16 ## Abstract 17 18 This ERC describes a standard for creating and updating identities with a limited use of blockchain resources. An identity can have an unlimited number of `delegates` and `attributes` associated with it. Identity creation is as simple as creating a regular key pair ethereum account, which means that it's free (no gas costs) and all ethereum accounts are valid identities. Furthermore this ERC is fully [DID compliant](https://w3c-ccg.github.io/did-spec/). 19 20 ## Motivation 21 22 As we have been developing identity systems for the last couple of years at uPort it has become apparent that the cost of identity creation is a large issue. The previous Identity proposal [ERC725](https://github.com/ethereum/EIPs/issues/725) faces this exact issue. Our requirements when creating this ERC is that identity creation should be free, and should be possible to do in an offline environment (e.g. refugee scenario). However it must also be possible to rotate keys without changing the primary identifier of the identity. The identity system should be fit to use off-chain as well as on-chain. 23 24 ## Definitions 25 26 * `Identifier`: a piece of data that uniquely identifies the identity, an ethereum address 27 28 * `delegate`: an address that is delegated for a specific time to perform some sort of function on behalf of an identity 29 30 * `delegateType`: the type of a delegate, is determined by a protocol or application higher up 31 Examples: 32 33 * `did-jwt` 34 * `raiden` 35 36 * `attribute`: a piece of data associated with the identity 37 38 ## Specification 39 40 This ERC specifies a contract called `EthereumDIDRegistry` that is deployed once and can then be commonly used by everyone. 41 42 ### Identity ownership 43 44 By default an identity is owned by itself, meaning whoever controls the ethereum account with that address. The owner can be updated to a new key pair account or to a multisig account etc. 45 46 #### identityOwner 47 48 Returns the owner of the given identity. 49 50 ```js 51 function identityOwner(address identity) public view returns(address); 52 ``` 53 54 #### changeOwner 55 56 Sets the owner of the given identity to another ethereum account. 57 58 ```js 59 function changeOwner(address identity, address newOwner) public; 60 ``` 61 62 #### changeOwnerSigned 63 64 Same as above but with raw signature. 65 66 67 ```js 68 function changeOwnerSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, address newOwner) public; 69 ``` 70 71 ### Delegate management 72 73 Delegates can be used both on- and off-chain. They all have a `delegateType` which can be used to specify the purpose of the delegate. 74 75 #### validDelegate 76 77 Returns true if the given `delegate` is a delegate with type `delegateType` of `identity`. 78 79 ```js 80 function validDelegate(address identity, bytes32 delegateType, address delegate) public view returns(bool); 81 ``` 82 83 #### addDelegate 84 85 Adds a new delegate with the given type. `validity` indicates the number of seconds that the delegate will be valid for, after which it will no longer be a delegate of `identity`. 86 87 ```js 88 function addDelegate(address identity, bytes32 delegateType, address delegate, uint validity) public; 89 ``` 90 91 92 #### addDelegateSigned 93 94 Same as above but with raw signature. 95 96 97 ```js 98 function addDelegateSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 delegateType, address delegate, uint validity) public; 99 ``` 100 101 102 #### revokeDelegate 103 104 Revokes the given `delegate` for the given `identity`. 105 106 107 ```js 108 function revokeDelegate(address identity, bytes32 delegateType, address delegate) public; 109 ``` 110 111 112 #### revokeDelegateSigned 113 114 Same as above but with raw signature. 115 116 117 ```js 118 function revokeDelegateSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 delegateType, address delegate) public; 119 ``` 120 121 122 ### Attribute management 123 124 Attributes contain simple data about the identity. They can be managed only by the owner of the identity. 125 126 127 #### setAttribute 128 129 Sets an attribute with the given `name` and `value`, valid for `validity` seconds. 130 131 132 ```js 133 function setAttribute(address identity, bytes32 name, bytes value, uint validity) public; 134 ``` 135 136 137 #### setAttributeSigned 138 139 Same as above but with raw signature. 140 141 142 ```js 143 function setAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes value, uint validity) public; 144 ``` 145 146 147 #### revokeAttrubte 148 149 Revokes an attribute. 150 151 152 ```js 153 function revokeAttribute(address identity, bytes32 name, bytes value) public; 154 ``` 155 156 157 #### revokeAttributeSigned 158 159 Same as above but with raw signature. 160 161 162 ```js 163 function revokeAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes value) public; 164 ``` 165 166 167 ### Events 168 169 #### DIDOwnerChanged 170 171 MUST be triggered when `changeOwner` or `changeOwnerSigned` was successfully called. 172 173 174 ```js 175 event DIDOwnerChanged( 176 address indexed identity, 177 address owner, 178 uint previousChange 179 ); 180 ``` 181 182 183 #### DIDDelegateChanged 184 185 MUST be triggered when a change to a delegate was successfully made. 186 187 188 ```js 189 event DIDDelegateChanged( 190 address indexed identity, 191 bytes32 delegateType, 192 address delegate, 193 uint validTo, 194 uint previousChange 195 ); 196 ``` 197 198 199 #### DIDAttritueChanged 200 201 MUST be triggered when a change to an attribute was successfully made. 202 203 204 ```js 205 event DIDAttributeChanged( 206 address indexed identity, 207 bytes32 name, 208 bytes value, 209 uint validTo, 210 uint previousChange 211 ); 212 ``` 213 214 215 ### Efficient lookup of events through linked identity events 216 217 Contract Events are a useful feature for storing data from smart contracts exclusively for off-chain use. Unfortunately current ethereum implementations provide a very inefficient lookup mechanism. By using linked events that always link to the previous block with a change for the identity, we can solve this problem with much improved performance. Each identity has its previously changed block stored in the `changed` mapping. 218 219 220 221 1. Lookup `previousChange` block for identity 222 223 2. Lookup all events for given identity address using web3, but only for the `previousChange` block 224 225 3. Do something with event 226 227 4. Find `previousChange` from the event and repeat 228 229 230 231 Example code: 232 233 234 ```js 235 const history = [] 236 previousChange = await didReg.changed(identity) 237 while (previousChange) { 238 const filter = await didReg.allEvents({topics: [identity], fromBlock: previousChange, toBlock: previousChange}) 239 const events = await getLogs(filter) 240 previousChange = undefined 241 for (let event of events) { 242 history.unshift(event) 243 previousChange = event.args.previousChange 244 } 245 } 246 ``` 247 248 249 ### Building a DID document for an identity 250 251 The primary owner key should be looked up using `identityOwner(identity)`. This should be the first of the publicKeys listed. Iterate through the `DIDDelegateChanged` events to build a list of additional keys and authentication sections as needed. The list of delegateTypes to include is still to be determined. Iterate through `DIDAttributeChanged` events for service entries, encryption public keys and other public names. The attribute names are still to be determined. 252 253 254 ## Rationale 255 256 For on-chain interactions Ethereum has a built in account abstraction that can be used regardless of whether the account is a smart contract or a key pair. Any transaction has a `msg.sender` as the verified send of the transaction. 257 258 259 Since each Ethereum transaction has to 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 3rd party funding services or receiver pays without any fundamental changes to the underlying Ethereum architecture. These kinds of transactions have to be signed by an actual key pair and thus can not be used to represent smart contract based Ethereum accounts. 260 261 262 We propose 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. 263 264 265 ## Backwards Compatibility 266 267 All ethereum accounts are valid identities (and DID compatible) using this standard. This means that any wallet provider that uses key pair accounts already supports the bare minimum of this standard, and can implement `delegate` and `attribute` functionality by simply using the `ethr-did` referenced below. As the **DID Auth** standard solidifies it also means that all of these wallets will be compatible with the [DID decentralized login system](https://github.com/decentralized-identity). 268 269 270 ## Implementation 271 272 [ethr-did-registry](https://github.com/uport-project/ethr-did-registry/blob/develop/contracts/EthereumDIDRegistry.sol) (`EthereumDIDRegistry` contract implementation) 273 274 [ethr-did-resolver](https://github.com/uport-project/ethr-did-resolver) (DID compatible resolver) 275 276 [ethr-did](https://github.com/uport-project/ethr-did) (javascript library for using the identity) 277 278 279 ### Deployment 280 281 The address for the `EthereumDIDRegistry` is `0xdca7ef03e98e0dc2b855be647c39abe984fcf21b` on Mainnet, Ropsten, Rinkeby and Kovan. 282 283 ## Copyright 284 285 Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). 286