Skip to content

Identity on Ethereum

Robert-Reinder Nederhoed edited this page Jan 28, 2016 · 26 revisions

In our distributed Identity framework we outlined the main ideas as we could implement on Bitcoin's blockchain and our Distributed Hash Table extension to it for storing objects and authenticating object updates. We then developed a KYC framework and a prototype on that framework.

We can now attempt to create the Identity implementation on Ethereum. We are grateful to Ethereum, ConsenSys, Factom, IDCubed and other developers who helped us hone the ideas found below.

Ethereum concepts

  1. Ethereum has a notion of an account, unlike the bitcoin. Account has the associated private/public keys.
  2. Ethereum has a notion of a contract, which is a code executed by Ethereum nodes.
  3. Unlike a bitcoin transaction that goes from many inputs to many outputs, Ethereum transaction goes from one account to another, or from one account to a contract.
  4. Contract is code that can also store key-value pairs. This makes it possible to manage identities. This contract store is expensive, and with high probability we will move the part that do not require strong consensus, to a separate store (DHT).
  5. In DHT-based design we relied on object versioning where versions formed a linked list. In Ethereum we forego this approach and rely on a combination of transactions and the current identity state in Identity contract's store.

##GOALS

  1. Support multiple identities per party.
  • Achieved by having separate Ethereum accounts (addresses)
  1. The ability to change keys, while preserving the identity
  • Achieved by changing Ethereum accounts and transferring ownership to the new account
  1. Identity theft/loss mitigation
  • Multiple custodianship of identity can be easily added (e.g. with incremental multi-sig)
  1. Identity attributes - public attributes you might see on a social profile.
  • Each identity has a key->value store of arbitrary size
  1. Validate transactions sent to other contracts with the identity contract.
  2. Identity needs an identifier, a stable ID. This ID is generated by the contract when Identity is created and can not be changed.

Extra goals

  1. Preventing identity spam with bonds (used by SIN).
  2. Merkle tree of all changes (used by SIN).
  3. Full re-validation. Ethereum's contract store allows lightweight client to rely on miner nodes doing the Identity state change validation. This way lightweight client can request only the latest Identity from the full node. But it is imperative for any full node to be able to verify that miners did not lie. With this design it is possible to validate Identity state transactions from all transactions to Identity contract, starting with the first transaction that created the Identity.

NON-GOALS

  1. Unique names/aliases. We do not want to create another name squatting place.

Account migration

Identity on Ethereum will be owned by an account. Migrating Identity to another set of keys means changing the account which owns this Identity. There are 4 cases when you need to migrate to another account. In all cases a simple custodianship procedure will work. The procedure described below is based on a similar idea of a multi-sig transaction in bitcoin: if 2 out 3 custodian accounts confirmed the migration from A to B (by sending a transaction setting new owner to B), it is done. If only one did it, Identity is in a temporary lock mode. Lock means this Identity can not issue transactions to any contracts which support this algorithm.

This scheme can be easily modified to support complex factors like custodian's level of importance, time of day, quantity of transactions, amount of money, etc.

  1. Key expiration. It is a good security policy to change your keys on a regular basis, and as account is tied to the keys in Ethereum, to change the keys - you need to migrate your Identity to another account.
  2. Key loss. When you lose the keys to your account, you need an Identity recovery mechanism.
  3. Key theft. When someone stole your account private keys, they should not be able to easily usurp your Identity.
  4. Key revocation. In an organizational setting, when employee resigns or is fired, the boss needs a way to lock the Identity.
  5. Custodianship change. Custodians must be specified when Identity is created. Custodians can resign, die, their keys can get stolen, they can go rogue, etc. We need a procedure to change a custodian. A simple recourse is for two other custodians to agree to replace a custodian. More complex schemes can be developed.

Validating your transactions

Suppose you send an order to a merchant, and you specify your Identity. Ethereum contract A can pass a sender to the Identity contract to check that this sender owns the Identity, and the Identity is not locked.

Ethereum Contract (sketch)

STABLE_ID_IDX = 0
ACCOUNT_IDX = 1
LAST_RESERVED_IDX = 1      # last reserved index in every identity's key->value store
JOHNNY_DRAMA = 0
data accountToIdent[][]    # identity registry keyed on account (key->value store per identity)
data idToIdent[][]         # identity registry keyed on stable id

def init():
  # nothing special about the first dude, except them being awesome

def create_id(custodian1, custodian2):
  # creates an identity for the sender, if it doesn't exist already
  # TODO: charge extra for creation (GOALS#Bond)
  if not self.accountToIdent[msg.sender]:
    # attribute store for this identity
    stableId = sha256(msg.sender)

    # for fun
    if not JOHNNY_DRAMA:
      JOHNNY_DRAMA = stableId
    # no more fun, promise

    data atts[]
    atts[STABLE_ID_IDX] = stableId
    atts[ACCOUNT_IDX] = msg.sender
    self.accountToIdent[msg.sender] = atts
    self.idToIdent[stableId] = atts

def get_current_owner(stableId): # returns the current owner of stableId
  atts = self.idToIdent[stableId]
  if atts:
    return(atts[ACCOUNT_IDX])

def get_stable_id(account):
  # returns the stable id of account, useful for validation of messages by other contracts
  atts = self.accountToIdent[account]
  if atts:
    return(atts[STABLE_ID_IDX])

def delete_id():
  # delete the identity of the sender, if it exists
  # maybe just: self.update_id(0)
  atts = self.accountToIdent[msg.sender]
  if atts:
    self.idToIdent[atts[STABLE_ID_IDX]] = 0
    self.accountToIdent[msg.sender] = 0 # not sure how to delete entry

def update_id(new_ident):
  # transfer ownership of the sender's identity to the specified address [new_ident]
  atts = self.accountToIdent[msg.sender]
  if atts:
    self.idToIdent[atts[STABLE_ID_IDX]] = atts
    self.accountToIdent[msg.sender] = 0 # not sure how to delete entry
    self.accountToIdent[new_ident] = atts

def set_attr(key, value):
  # update an attribute in the sender's store
  if key > LAST_RESERVED_IDX:
    atts = self.accountToIdent[msg.sender]
    if atts:
      atts[key] = value

def get_attr(key):
  # check an attribute's value in the sender's store
  atts = self.accountToIdent[msg.sender]
  if atts:
    return(atts[key])
Clone this wiki locally