Introduction

Litentry is a second layer protocol and infrastructure based on Substrate. It focuses on Identity of person and IoT devices, and the authorization and permissions granted by the Person or IoT devices.

The objective of Litentry is to

  1. make it possible for any third-party to allow users to access the their website or offline services using an Substrate Account ID as an identifier or an access token. It based on Substrate so it could easily integrated cross chain nature of Polkadot Network. So it could connect with either the existed Blockchain ecosystem like Ethereum and Substrate.

  2. Get back the control of user access history and privacy data generated in using the app or the service, a user is able to store these encrypted identity information locally or on a authorized cloud service.

  3. Share the identity anonymously between different platforms, a user do not need to create multiple accounts in order to use different services, and prevent these services for building user profile.

  4. The protocol includes the authentication of IoT devices, which helps the organization and person to implement easy identity access management.

Architecture

The protocol is mainly constructed with following parts:

Concept of Decentralization

The decentralization of Litentry includes following aspects:

  • Decentralization of identity storage: User data, including identity credential, should be storage in the user's owned devices, instead of the central data server of service provider.

  • Dentralization of idenity authentication: The identity validator connect to the decentralized network periodically, and it could validate the authentication request independently.

  • Decentralization of identity ownership: The relationship of data, person, and identity could be validated with cryptographic calculation, and it is also record in the decentralized network instead of regular centralized serviec like Certificate Authority used in HTTPS protocol

  • Decentralization of Identity Data Allocating: The user data generated when using third party applications/services could be processed by the resolver function on Litentry Network, thus provider user a trustworthy data, with allocate data from multiple applications/services, user are able to create valuable user profile like health info, shopping history, etc.

Definitions

  • User: The origin of data, it a person who holds identities or IoT devices.
  • Identity: It is a generalized concept of identity, not only include the identity of person, but also any thing could generate claims like IoT devices. A person could own multiple identities, like an identity in Germany, an identity as E-Resident in Estonia, or an identity as an game player.
  • Authorization: The permission in the reality or the claim in the blockchain world. It is a piece of data that could prove the ownership to a capability or a real thing. Like the permission to read the age data of a person, or the ownership of a 3D printer on a certain day.
  • External Data: It is the data generated when using the applications/services, like the shopping history when a user shopping in e-store, or the age data read from the aforementioned age proving request.

Network Interoperability

Based on Substrate Network, Litentry aims to become a fundamental part in the Web3 infrastructure.

// TODO

  • Network Layer: Polkadot is here to connect different blockchains
  • Runtime Layer: The Litentry Pallet could be used for other Substrate network builders.
  • Application Layer: Small business could build smart contract on Litentry network.

Privacy data feeding and protection

The current verification process has problems of privacy data generation.

  1. If a user come to Hotel with his digital key (claim). The smart lock itself could generate data, and each time user come into the room, these pieces of data is generated, but they are harvested by the hotel, and never reach to user.

  2. The Data generated are combined with user's accountID (public address), when these authorizations (claims) be more enough, it will be practical for the external companies to monitor the on-chain state, and build user profile.

To resolve this problem, and let the user get their data, we have designed our new method based on Substrate offline worker and crypto algorithms based on Schnorr25519.

  1. To protect user's data, we migrate the data generation process on to Substrate, after the verification process, the crucial arguments like user address, verifier, time, token hash will be send into blockchain with a verifier extrinsic. Which is independent with off-line verification, thus it will not affect the verification time. Then the data will be generated in offchain worker, generate access token to user's storage, and then feed the data back to user.

  2. To protect the user data, we will use HDKD feature to periodically generate new soft derivated key pairs for certain user. Verifier could prove the the address is belongs to the parent keypairs with crypto algorithms. Thus user will not need to always show one certain public address. Another key point is to use ring signature, which will hide user's signature behind bunch of people. Child address generation feature is already implemented in our crypto wallet and Ring signature is our current experiment direction.

The workflow of user data feed could be seen in the following diagram

User Data Feed Diagram

Related Article about Off-Chain Worker: https://www.parity.io/substrate-off-chain-workers-secure-and-efficient-computing-intensive-tasks/

SubAuth

Check Web Demo here

Repository: https://github.com/litentry/LitentryWebDemo

On how to play with the web demo please refer to this article.

SubAuth is a protocol for web app applications to achieve a Substrate based authentication.

The Object

  • It should allow users to use his/her owned Substrate address to login to a third party website (that supports this login method).
  • It should be easy to use and reasonably easy to setup.
  • It should not compromise the security of the user's Substrate account.
  • It should allow users to recover their credentials in case of loss or theft.
  • It should not require knowledge of Cryptography or Blockchain with authentication.
  • It should have reasonable latency for a login system.
  • It should not cost users gas (or money) to login.
  • It should be reasonably easy for developers to implement in their apps.

The Implementation

  1. User on a third party website and click login with Litentry Button
  2. A preset account will come if user has logged before in the computer, or a QR scanner comes out for user to scan his/her Substrate account QR code.
  3. At this time the third party website send a transaction to Litentry network with a challenge string and its receiver server address. And sign a JWT with challenge and server address embedded in it.
  4. User now has to open the mobile app (best integrated with Substrate light client), it has watched the event of the auth request, and then sign the JWT with its private key and then send the signed double signed JWT to the server address.
  5. The server proved the token received by the user and then finish the logging process.
  6. After the usage of the third party web application or service, third party allocated the user browsing data/history and query the user's data resolver address, then user data is send back to the resolver and being process and harvested into user's own database.

Runtime

Github Repository: https://github.com/litentry/litentry-runtime

As Pallet: https://github.com/litentry/substrate/blob/master/bin/litentry/pallets/template/src/lib.rs

Abstract

The identity runtime protocol abstract all the persons and devices authorization scenario, includes three basic definitions:

  1. Identity Registry: a pre-defined key pair to present a person or a device.

  2. Token: a non-fungible token issued by the identity.

  3. Data: the related identity data, like identity meta information and token specification.

Identity Runtime Protocol

Examples:

Person ID chain:
  • Identity Registry: crypto key pairs bind to national identity number;

  • Token: a token created by the person, which could be used to validate the age;

  • Data: the data of the person, e.g. birth date and place, gender, etc.

Lock Chain:
  • Locks Registry: crypto key pairs bind to the smart IoT lock;

  • Token: a token created by the lock, which could be used as an entry key.

  • Data: the definition of the token, e.g how many times could one token be used.

Features

Cross Chain Validation

Such a protocol could be easily combined for the Polkadot cross chain feature, thus could realize many new ideas:

For example, the entry token on the lock chain need to be combined together with the personal ID chain, the entry token is only valid if the user's age is more than 18. The other personal data will not be exposed at the same time.

Runtime Specific Data Operation:

An IoT device manufacturer could have its own data operation functions, for example, it may harvest the data from all the temperature sensors and pay DOT to the sensor owners.

Data Linking

The large data bind to the identity owner, i.e. person or devices, will be saved into an IPFS data server, the entry hash link will bind to their identity. The benefit of it is once the data updates, the old link will be also disabled. In order to always get the available data, others need to ask permission from the user.

Authentication Mobile App

Github Repository: https://github.com/litentry/litentry-authenticator

Mobile App Abstract

Personal users would like to use an Wallet Application to manage all its identities, it could also become a Hub connected to different interest IoT devices. For example, directly buying the authorization or the data from other IoT devices. With the advantage of GPS of mobile phone, it could further integrate with LBS (Location Based Services).

In order to work in a fully decentralized scenario, itself also need to integrate a light client, where could keep a user's private key in a secure environment provided by Android or iOS.

Mobile Application Concept Sketch:

Identity and Token Creation Example Token Usage Example

Middleware

API of data server

Live Server: http://112.125.25.18:3000

The Litentry API behavior as a middle layer connects the runtime module and frontend applications for users.

API Design

It mainly includes:

  • Event listener and off-chain caching server: With cached data it reduces the query load on the blockchain, furthermore, it saves the caching data on the centralized database in order to improve the speed of application-based blockchain query, like Infura for Ethereum. A relay script server is also built here, to automatically trigger an event on periodically regarding block generation.

  • IPFS caching server: especially for the large data from IPFS, the server will caching the data to the server.

  • GraphQL validation and query server: validate the authorization tokens with HTTPS request for IoT devices or application.

  • Javascript binding library: The javascript binding library will directly connect the front-end applications with Blockchain, for example, React or React Native applications.

Info Server Architecture

API

GraphQL Data Server

Githun Repository: https://github.com/litentry/litentry-juniper-api

Our GraphQL Api sever is designed as bridge between substrate blockchain and app/device. The server framework is juniper based on hyper.

Hyper is a fast, safe HTTP implementation written in and for Rust. Hyper implement all request/response via "async IO" (non-blocking sockets) via the Tokio and Futures crates. Juniper is GraphQL query implementation in Rust, provide most efficient and most flexible query service.

For the interface to substrate part, most of code from substrate code base. Functionalists include get metadata, query storage, send transaction and subscription.

VerifyToken

fn verify_token(token_hash: String, signature: String, raw_data: String)

Any user could verify the token owner by sending the token with its attached info to the data server, data server will proved that if the sender is the token owner. This function will check if the owner of the token is the same as the signer of the transaction.

  • token_hash: The ID of the token
  • signature: The signature of the token information signed by the sender
  • raw_data: The raw data of the message

The message could be generated by the following code.

const dataToBeSigned = `{ownerAccountId}:{tokenHash}:{timeStamp}`;
const signature = sign(seed, dataToBeSigned);

GetTokenInfo

fn get_token_info(token_hash: String)

token_hash: The ID of the token

Get token related information like token owner and the identity which owns the token.

Chain State Storage

Identity Related

Identities: T::Hash => IdentityOf<T>;
IdentityOwner: T::Hash => Option<T::AccountId>;

IdentitiesCount: u64;
IdentitiesArray: u64 => T::Hash;
IdentitiesIndex: T::Hash => u64;

OwnedIdentitiesCount: T::AccountId => u64;
OwnedIdentitiesArray: (T::AccountId, u64) => T::Hash;
OwnedIdentitiesIndex: T::Hash => u64;

Token Related

AuthorizedTokens: T::Hash => AuthorizedTokenOf<T>;
AuthorizedTokenOwner: T::Hash => Option<T::AccountId>;
AuthorizedTokenIdentity: T::Hash => Option<T::Hash>;

AuthorizedTokensCount: u64;
AuthorizedTokensArray: u64 => T::Hash;
AuthorizedTokensIndex: T::Hash => u64;

OwnedAuthorizedTokensCount: T::AccountId => u64;
OwnedAuthorizedTokensArray: (T::AccountId, u64) => T::Hash;
OwnedAuthorizedTokensIndex: T::Hash => u64;

IdentityAuthorizedTokensCount: T::Hash => u64;
IdentityAuthorizedTokensArray: (T::Hash, u64) => T::Hash;
IdentityAuthorizedTokensIndex: T::Hash => u64;

Extrinsic

issueToken

fn issueToken(to, identity_id, cost, data, datatype, expired)

Issue a token of an owned identity to certain account.

  • to: AccountID, the future owner of the token
  • identity_id: Hash, the id of the identity who issue the token
  • cost: Balance, the transfer cost of the token
  • data: byte, The data stored in the token
  • data_type: byte, the type of the data represent in byte
  • expired: byte, which define the expired date of the token

registerIdentity

fn registerIdentity()

Register a new identity for this account.

registerIdentityWithId

fn registerIdentityWithId(identity_id)

Register a new Identity with existed identifier as Identity ID, this is useful when register a third party devices or services. For example, a user buy a new IoT camera, there could already exist a identifier on the back of device reserved for the buyer.

  • identity_id: Hash, the identifier to be used as identity ID

transferToken

fn transferToken(to, token_id)

Transfer a owned token to another account

  • to: AccountId, the future owner of the token
  • token_id: Hash, the ID of the transferred token

Types

{
  "Address": "AccountId",
  "LookupSource": "AccountId",
  "IdentityOf": {
    "id": "Hash"
  },
  "AuthorizedTokenOf": {
    "id": "Hash",
    "cost": "Balance",
    "data": "u64",
    "datatype": "u64",
    "expired": "u64"
  }
}

When using with Polkadot.js App you will need to addthe above Litentry's types so it can encode and decode the extrinsic correctly, copy the following code to the text field on "developer" tabs: https://polkadot.js.org/apps//#/settings/developer .

Example on Overwrite Types on Polkadot Apps

FAQ

What is the common use case of the identity protocol?

In our protocol, we basically analog most authorization scenarios into a common protocol with four elements: d1. Person or IoT devices Identity d2. Authorization d3. Member's who holds the Authorization d4. External data related to the Identity. Here the Authorization token is similar to the ERC721 standard but not the same, it could be used to help understand the idea. The common idea is that the authorization is a piece of data created by the d1. Person or IoT devices Identity and send to a d3. Member. The Specification of each d1. Person or IoT devices Identity will be saved as d4. External data. This ownership and specification could be proved by the whole network.

Take door lock for example: An Airbnb host could use a smart lock to issue the digital key on our protocol, the user who has Parity-Signer Wallet (for example) could fetch the token data (d2. Authorization) and send it to the lock by a p2p way (Bluetooth for example) for validation. The lock will interpret the token data with its own pre-defined interpreter function (on-chain or off-chain, still need to think), like how many time a user may enter, what is the entry duration. By this way, the d1 Person or IoT devices could be shared in a decentralized and a securer way. We suppose such kind of authorization would fit the normal business (hotel) and sharing economy very well.

Why use non-fungible-token as key rather than a signed message, e.g. a message signed using the digital key and can be validated by the lock off-chain.

Signing transaction way works in authorization and it is simple. The basic of token authorization model is to validate a piece of information which is sent by the owner. These pieces of messages could be encrypted in the transaction as a message memo, and even transfer to others with last message data include or using a UTXO model.

In comparison, The "non-fungible-token way" or "ERC721 Standard way" gives a state map of all the authorizations and identity of the IoT device or people. The advantages are:

  1. The relationship between d1. Person or IoT devices Identity d2. Authorization d3. Member's who holds the Authorization could be checked easily, and this is very useful in many scenarios. For example, in an apartment sharing business, the user could know how many keys (tokens) are existed for a certain lock at the moment and further check the ownership of all other keys (tokens).

  2. Bulk transactions are more efficient and easy to update (even no need for loops). For example, an identity could easily recall all his authorized tokens, or updates existed tokens information.

  3. A state explicitly shows the relationship and will be easy for understanding, and cross-chain programming. The further cross-chain function call will be based on the state information on different parachains.

In addition, the off-chain validation is still possible since the proof of token could directly be the identity (hash) of the token, and its information is retrievable from the state map. User with this information could send it to an off-line validator. ( Or a compromise way is that a validator regularly syncs with blockchain for the tokens and owners of identity, or totally an online validator).

why do we need a GraphQl server? Is it worth the trade-off (complexity, centralization) as opposed to requests being validated directly on chain?

A GraphQl is basically an API server, we have two different views of its usage.

  1. In a short view, since currently there are not so many libraries like oo7 which can directly connect with Substrate Runtime and external IPFS storage. An API server will currently offer fast development and could be used as a good demo for application developers, it could be regarded as Infura on Ethereum.

  2. In a long-run view, we supposed it could be a query server for historical and caching server, which could offer fast access for the historical data, good infographics from database, caching the data by event listeners and queries, and reduce the load of the blockchain. Though it is with tradeoffs and comprises to the decentralized architecture, the most important validation and issuing functions will still be accessible directly by Blockchain.

So in summary, the GraphQl API server is a necessary-to-have thing, but whether to use it will be mostly chosen by the application developer.

What is the difference between ID Chain and Lock Chain and the need for each?

Litentry is aimed to offer a basic protocol and related framework, which could be used for fast application development. Both the ID chain and Lock chain are one application based on it.

The traits of these two chains are in the same protocol with slight differences. Take ID chain, for example, The registry could be the citizen offices in a different city. Permissions would be that the different Right bind with certain people, like (boolean value for over 18 age, int value for tax level, etc). Permissions could be assigned to only one Member, but a member could have more than one Permissions.

The same in lock chain is that the Locks are a list with all different kinds of lock, the lock owner who has the private key of the lock may issue the access right token to the member, like multiple entry token, or a one-day-pass token. A member could have a different token with different locks, but one token could be only assigned to one person.

Though there are similarity and difference based on the implementation of the protocol of different traits of parachain. The main difference between these parachains is that they have different cross-chain function based on that. The cross-chain function could be e.g. A insurance (which authorized insurance token) calculate the healthy insurance working permit of ID Chain; the Lock chain will issue the entry token of a shisha bar with validating the age on ID chain; A gym will offer a special membership token to the people who have the entry token of co-working space, etc. All these cross-chain issue and validation will be defined by the cross-chain function on different para chains with the same protocol.

In addition to that, separate these chains will gain the flexibility to different business scenarios by adding the parachain-scope function. For example, an IoT device Chain with temperature monitors of different locations. A value of all the registered temperature monitors on 24:00 every day could be harvest directly to external storage. But if a user wants to get a piece of detail information on a certain time, he needs to has an authorization token for querying that data.