Skip to content

aragonzkresearch/leagueofidentity

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

League of Identity - PoC

Overview of the system

This repository provides a PoC implementation of the League of Identity (LoI) system described in this note.

LoI is a network of nodes with the following functionalities. LoI publishes what is called a master public key (MPK). Alice logs into her own Google (or Facebook, Twitter, ...) account alice@gmail.com from a given LoI website and gets what is called an OAuth 2 access token. Alice can send the so obtained access token to a sufficiently large set of nodes of LoI requesting to these nodes a cryptographic token corresponding to her email address and a given month and such set of nodes, upon verifying that the access token is valid, send back to Alice a set of token shares by means of which Alice can compute the (full) token corresponding to her email address and the specified month. The token can be relative to other identity information like a phone number or the social security number etc. (see below). The token can be used for the following functionalities.

Functionalities of the LoI token

  • Encryption. Bob can use the MPK of LoI to encrypt a message associated to alice@gmail.com and a given month and can publish the resulting ciphertext on a blockchain or send it directly to Alice. Alice can use the previously obtained token to decrypt the ciphertext received by Bob and recover the secret message. We remark that the token is different from the access token.
    • Group encryption. Similarly, the token can be associated to a group. For instance, if Alice belongs to the company oldcrypto the token can be associated to the domain @oldcrypto.com and anyone can send encrypted messages to all members of such company. Specifically, if for instance @oldcrypto.com is a Google Business domain, Alice and Bob, belonging to the company, can log into their Google accounts and get tokens to decrypt ciphertexts associated to @oldcrypto.com.

See here for other examples of applications of identity-based encryption in web3.

  • Signatures. The token can be used by Alice to sign transactions over blockchains (e.g. Cosmos ones) so that one can form a Decentralized Autonomous Organization (DAO) based on specific rules. Consider the following applications scenarios:
    • The DAO of @oldcrypto.com can be created in the obvious way by issuing corresponding tokens to users of Gmail accounts with domain @oldcrypto.
    • LoI can issue tokens to the holders of valid digital identity cards (DIC) and this would allow to create e.g., a DAO of the citizens of a given town or the DAO of < 18 years old teenagers.
    • LoI can issue tokens corresponding to Instagram accounts with more than 1 million of followers thus creating a DAO of Influencers.
    • LoI can issue tokens corresponding to Ethereum NFTs held in a smart contract. The LoI token can be then used as a bridge in other blockchains or can be used in Ethereum itself for other functionalities: e.g., ZK proofs, encrypted data for DAO members. Currently, we support tokens for Ethereum addresses (possibly associated with their Wei balance) thus allowing to create a bridge between Etherem and other blockchains and to encrypt data with respect to Ethereum addresses. We also support the option to restrict the nodes to grant the token only to an Ethereum address that holds at least X Wei.
    • LoI can issue tokens corresponding to Facebook accounts who are members of a given Facebook page and the LoI token can be then used e.g., on Ethereum or other blockchains as a mean to create a DAO of the members of that page. In particular the administrators of the page can create a bridge between Facebook and web3 applications.
    • The LoI tokens could be used as anti-spam tool, specifically the token could be related to accounts that encompass properties that are hard to forge on large scale. The current demo for instance allow to get tokens for facebook accounts with at least X friends. More stringent might be required to combat bots.

Moreover we envision the signature to satisfy the following property:

  • Efficient on-chain verification. The verification of the signature should be efficient for web3 applications. For instance, it is efficient to verify signatures of digital identity cards off-chain but verifying such signatures on Ethereum would consume too much GAS. Instead, the LoI signatures for digital identity cards should be efficiently verifiable in Ethereum and other blockchains. See here for example of Ethereum smart contracts using LoI.

We stress that LoI aims at offering both encryption and authentication/signatures at the same time: satisfying these two properties together is usually more challenging than achieving just one of them. Encryption+signatures allow powerful applications, for instance a DAO of @oldcrypto.com can have encrypted proposals readable only by its members.

Currently supported providers

The current demo supports the following providers:

  • google: associate as identity the email address set in the user's Google account.
  • facebook: associate as identity the email address set in the user's Facebook account.
  • google.phone: use Google as provider but associates as identity the phone number (when visible) set in the user's Google profile rather than the user's email address.
  • dic.it: the provider dic.it is for Italian digital identity cards (tested on v3.0). It can associate as identity the social security number of the citizen or other info depending on the options (see below).
  • eth: associate as identity an identity of the form wei@addr where addr is an Ethereum address and wei is the amount of Wei owned by the given adddress addr. With the option -anon the token will be instead associated to the identity 0@addr, that is anonymyzing the quantity of Wei held by addr.
  • nintendo: associate as identity the id of your Nintendo account. Thought it is not implemented yet, it will be easy to add the following option: a Nintendo gamer is granted the token only if he/she participates in a given Nintendo Switch Online game (e.g., Animal Crossing) and also to restrict the token only to gamers with specific state/progress in the game.

Disclaimer about the Nintendo provider

Do NOT use the Nintendo provider in any real world application outside your local computer. The demo in this repository is meant to be just a proof of feasibility about the possibility of implementing such mechanism for Nintendo in the future. Indeed, the current demo uses APIs that are not documented and might be insecure and not used properly. To deploy a LoI system with a Nintendo provider, Nintendo should be contacted and some efficient and secure APIs should be agreed and implemented by Nintendo and the LoI system should be adapted to them.

Installation

Installing the required packages

The demo has been tested using node v16.20.2. You can switch to such version using the command:

nvm install 16.20.2

For the web part the only required package is hello.js but a stand-alone version is embedded in the web folder. For the node.js part the required packages are (some of them could not be currently used) node-fetch, express, nocache, cors, commander, console, fs, shelljs, body-parser, web3, request-promise-native and noble-curves. To install them, run:

npm install --save express
npm install --save node-fetch@1.1.0
npm install --save nocache
npm install --save cors
npm install --save commander@11.1.0
npm install --save console
npm install --save fs
npm install --save shelljs
npm install --save body-parser
npm install --save web3
npm install --save request-promise-native
npm install --save @noble/curves@1.2.0

Note that for noble-curves we stick to the version 1.2.0 we used for the tests. You can try to use newer versions of node and noble-curves by tweaking the files (e.g., replacing require directives with import directives). Similarly for node-fetch and commander.

Prerequisites

It is strongly suggested that you create a Google developer account and get your client id (see below) that must be set in the file src/params.json. However, it is likely that you will be able to use the demo for the provider google even without that. Instead, for the provider facebook you need a pair of client id and secret id to fill the parameters resp. FACEBOOK_CLIENT_ID and FACEBOOK_SECRET_ID in the file src/params.json. For google.phone you need to fill the value GOOGLE_API_KEY in the same file with a Google API Key. For eth you need to fill the value INFURA_API_KEY in the same file with an Infura API Key.
For Nintendo you do not need any parameters or secrets but you should guarantee that the value nsoVersion in the src/params.json file equals the most recent Nintendo Switch Online version (e.g. 2.8.1 at time of writing).

Once you configured the parameters in params.json, you need to run a web server on the port 5000, for instance:

cd web
python3 -m http.server 5000

We used the port 5000 because the file main.js that implements the web page embeds a Google client id associated with domain localhost:5000 so changing port will not work with the client id we provided. It is strongly suggested that you create a Google developer account and setup your own project and get your own client id. Search the line containing the comment // client id in web/main.js and replace the corresponding value with your own client id . Similarly, for Facebook.

How to Use LoI modules

Get a Google or Facebook access token

Open the link localhost:5000 in your browser, and click on Get access token, you should get some view like the following:

Copy the so obtained access token in your clipboard. Note that it has a validity of 1hour. We assume henceforth that the variable access_token contains the text you previously copied to your clipboard. In this example I computed the token for my email vinciovino@gmail.com. You can select facebook from the menu to get a facebook access token. In the case of facebook the users will be associated to the email addresses specified in their personal profiles. Observe that in our example we are using a http website without TLS. This is only for simplicity. However, be aware that, since we are in the setting of OAuth implicit flow, using non-secure connections could make your application insecure.

Get a Nintendo access token

For Nintendo the flow is the following. Select facebook and click on Get access token, you will be redirected to a Nintendo login page. Input your credentials and you will land to a page with a button select this person. Right click on this button and copy the link. Return to the LoI webpage and paste it. The `access token`` will be shown in the console.

Note: though we still call the so obtained object access token, this is actually a session token code in the Nintendo API terminology. We keep the name access token for uniformity.

Get an Ethereum access token

For Ethereum the flow is identical except that you need to select ethereum from the menu and you will be asked to sign a message with your Metamask account. No transaction will be submitted on-chain and no GAS cost will be paid.

Compute the shares and run the LoI nodes

Henceforth, we assume to be working in the folder src. LoI is associated to two parameters: n, the number of nodes in the network, and t, the threshold of nodes who can reconstruct the secrets and break the security. Let us assume henceforth that t=2 and n=3. Run the following command:

node compute_shares.js -t 2 -n 3

You will get an output like:

DEBUG: 1-th coefficient of the 1-degree polynomial: 22616172845692563875646944834802029969319479005231155265423472447676397078828
master secret key: 32d37d4b4f967edd1a92553792ee8decfe9c5f3f49fce4a64e0fdfa4093e43a4
master public key: 98a13c5e305dbad1a006441e59234870103240416f4ec443b930fb6762f80e9254bd78bd3f27ad599df9d522ee724256054221f3bdfe3f3f5233927ec7bd5f585d2f5c7d65bb8efbc36ea8cc24464f65274c40a78cdabda2ec02b5b796d0a2a8
share of the server 1: 64d3ca258dacbeb286faad11268223a5d999ae7cb997798606d69888bcb58cd0
share of the server 2: 22e66faca225813fc0292ce2b073e15960d959b72933b266bf9d516e702cd5fb
share of the server 3: 54e6bc86e03bc1152c9184bc440777123bd6a8f498ce474678640a5323a41f27
reconstructed master public key: 98a13c5e305dbad1a006441e59234870103240416f4ec443b930fb6762f80e9254bd78bd3f27ad599df9d522ee724256054221f3bdfe3f3f5233927ec7bd5f585d2f5c7d65bb8efbc36ea8cc24464f65274c40a78cdabda2ec02b5b796d0a2a8

Henceforth we will denote by share1 (resp. share2, share3) the files containing the so computed share of the server 1 etc.

The previous computation simulates the computation of Distributed Key Generation (DKG) procedure with a trusted dealer. You can replace it with a real DKG procedure without trusted dealer but for simplicity we do not do that.

Now, you can run locally 3 LoI nodes with the following commands:

node loi_server.js -p 8001 -s share1 -i 1 &
node loi_server.js -p 8002 -s share2 -i 2 &
node loi_server.js -p 8003 -s share3 -i 3 &

Do not forget to store in the files share1, share2, share3 the previously computed values. This runs 3 servers on the respective ports 8001, 8002, 8003. Each server is associated with the indices resp. 1,2,3 provided with the '-i' argument.

Get a token from LoI.

Now you can run the following:

node get_token.js -A access_token -t 2 -n 3 -l 2 http://localhost:8002 3 http://localhost:8003

Do not forget to replace access_token with the value computed before (see above). The argument -A specifies the access_token. The arguments -t and -n first correspond to the aforementioned values t=2,n=3. The argument -l specifies a list 2 http://localhost:8002 and 3 http://localhost:8003 to denote that we want to request the token shares from the nodes with indices 2 and 3. If you want to do the request e.g. to the nodes 1,3 you would need to replace -l 2 http://localhost:8002 3 http://localhost:8003 with -l 1 http://localhost:8001 3 http://localhost:8003. Here, we request a token for the current month. Use the option -m month.year to get a token for a past month. The value month in the string month.year is an integer between 0 and 11 and year has the form XXXX. Moreover, use the option --group if you want a token for a group. Use the option -P provider to switch to a different provider (e.g., facebook); the default provider is google.

You will get an output like:

Value received by server 2 (http://localhost:8002): LoI..google..vinciovino@gmail.com..11..2023..a498c6a0508adbfe812475fbee2da1230fc2068dfd4d07e438ba59f7307cb637b87ff30a3b16a1bc3996c4ac202f2ad304247e020d293fb42f71f5e0c8e14dd5c8a8da925397cba2262453f85b83e3947f6fd3a6c8f937461a728712b4603414..ada3cfb63fd3fe0e45e0537dbeeb62c3a9b8e237a5a92c8a0fc47fc0223c7a7f0d0db5ea588f628a522d79fd8b8b75cc
Value received by server 3 (http://localhost:8003): LoI..google..vinciovino@gmail.com..11..2023..aa653eeeb7ec24a296a67980efd5b069013e3a1df79c879126036e7cf88932d4c32a85088e5a856d618744f2d2e7b42c0e31e25b7581ca10aee77cd0a4d80a039b868e71c730571441d8478b112f317cb79a6a7f06157550c4d7fa559f57681c..a1c5f1131b810fcf76bdc497b2fbf7ffefe3825886e229e85f7f86dc672637a80c8db0e972e8d101035a4e5d74fa80e9
reconstructed master public key: 88b8aa62727da6ab4a10d077a4e5cfe038695925f037db5b7c91efa824d1b7ad80056083077e592f00142ac6abf208d30e4b962b94e2fc8c759a7c6faab7b2f8718b3a8cb156da061176ddeaefb13a6c3568a9614608bddc67f982a1d710d28e
reconstructed token: af5c3a2d675f8750ea1a416c8064c912ccd46e935e16b31a1906532a1ab95646924c31f153a5e030d40118923e9421f5
Verification of reconstructed token: success.

Henceforth we will denote by mpk the so computed master public key. So, in the following commands whenever we will write e.g., mpk you need to replace it with the previous value. Similarly, for the string token. Note that the reconstructed mpk computed by the previous command is just used for debug purposes. In real applications one should use as master public key the one that is made public by the LoI members at the launch of the system.

Encrypt

Let us assume that the secret message to encrypt is the string aa and it is contained in the file msg. Run the following command to encrypt under my email vinciovino@gmail.com with the tag of December 2023:

node encrypt.js -k mpk -e vinciovino@gmail.com -m 11.2023 < msg

You will get something like:

ciphertext: 2.afacb96209bc9c9f9e8e1484aee1a42ecd08488f487cc30eac89bee7ebffb3327040e3bcf77c9378e646ec118fb9ba2004b734a0502f3c3df658660041659a5582ce9e662ccfefb68dd2a421227676a79b529a11d1c474526c253ff57cb15a82.6b5d

Henceforth, let us assume that the previous ciphertext is contained in the variable ciphertext.

Note that in order to encrypt for December we used 11.2023 not 12.2023. This is because the month field starts from 0, that is it is an integer between 0 and 11.

Decrypt

Now, you can decrypt with the following command:

node decrypt.js -T token -k mpk -e vinciovino@gmail.com -m 11.2023 -c ciphertext
Verification of token: success.
aa

You should get in the end the recovered message contained in the file msg.

Phone number encryption (phencryption)

With the provider google.phone you can specify phone numbers to the argument -e in the above commands and you will be able to encrypt/decrypt with respect to phone numbers that are verified in public profiles of Google users.

CCA2-security

With the option -cca2 to both encrypt.js and decrypt.js you can require security against adaptive chosen ciphertext attacks (IND-CCA2), the strongest form of security for encryption. The decrypted message will start with a character that is either 1 or 0 depending on whether the decryption was successful or not.

Signatures

The commands node sign.js and node verify.js allow resp. to sign and verify signatures. We defer the programs' interface to the help provided by the --help option.

Group encryption/signatures

For group encryption/signatures specify the --group option to the get_token.js command and specify the domain (e.g., oldcrypto.com) instead of a full email in the other commands.

Additional options

Anti-spam token

When using the facebook (resp. eth) provider you can specify the option --friends X (to all commands) to associate the token only to a Facebook user (resp. Ethereum address) with at least X number of friends (resp. with at least X Wei held by the address). This may have applications as anti-spam tool in blockchains since it makes harder to create fake users. In the case of the eth provider it can be also used to create e.g. the DAO of wealthy Ethereum users.

Anonymity

With the option -anonymous to get_token.js it is possible to request a token associated to an identity equal to the hex string representing the hash of the access token string specified to the argument -A; in such case you need to specify this string derived from the access token string to the argument -e of all other commands. If the provider is different from eth, for security the servers should check whether the access token has not been already used but this is not done in the current demo. For the provider eth, this option sets the identity equal to a string of the form 0@addr where addr is an Ethereum address. This option is not compatible with the provider nintendo.

For all providers different from eth and nintendo, this option is compatible with the option --group; in such case you need to specify identities of the form AT@domain to the argument -e of the encrypt.js, decrypt.js, sign.js, verify.js commands, where AT is the access token specified to the -A argument of the get_token.js command.

Digital Identity Cards

The flow to use digital identity cards (DICs) is the following. The following example is for the Italian DIC but we will later show how to generalize it to virtually any DIC that supports signing documents (not all DIC do support signing but in the near future many countries will adopt it). With the command:

node get_token.js  -t 2 -n 3 -l 2 http://localhost:8002 3 http://localhost:8003  -A null -P dic.it -j challenge.json 

one gets from the chosen LoI nodes (in this case the ones with indices 2 and 3) a challenge file challenge.json. Observe that we specify null as parameter to -A since no access token is actually needed for DICs. The file challenge.json contains some random challenges with corresponding generation times. The user is asked to sign this file with his/her own DIC within 30mins. In real world applications this file could be replaced by a contract in PDF form to be signed with the user's DIC as it is the case in many public administrations websites.

Let us say that the user signs the aforementioned file with his/her own DIC (this depends on the specific country, in Italy it can be done with the official App CIEID even though other Apps are available as well) and let us assume that the signed file is challenge.json-signed.p7m. Note that .p7m is the usual standard for signed files. Then the user submits the following command:

node get_token.js   -t 2 -n 3 -l 2 http://localhost:8002 3 http://localhost:8003  -A null -P dic.it -s challenge.json-signed.p7m

and gets something like:

DEBUG: the server 2 accepted the signed document.
LoI..dic.it..XXXXXXXXXXXXXXXXXXXX..11..2023..a498c6a0508adbfe812475fbee2da1230fc2068dfd4d07e438ba59f7307cb637b87ff30a3b16a1bc3996c4ac202f2ad304247e020d293fb42f71f5e0c8e14dd5c8a8da925397cba2262453f85b83e3947f6fd3a6c8f937461a728712b4603414..a72d41f75297ff2f735e34051fd643a2a6a3d06a8918406e8c0ef61b89127447182e3366652d5dc590bf2a9b3a0f8152..null..0
DEBUG: the server 3 accepted the signed document.
LoI..dic.it..XXXXXXXXXXXXXXXXXXXX..11..2023..aa653eeeb7ec24a296a67980efd5b069013e3a1df79c879126036e7cf88932d4c32a85088e5a856d618744f2d2e7b42c0e31e25b7581ca10aee77cd0a4d80a039b868e71c730571441d8478b112f317cb79a6a7f06157550c4d7fa559f57681c..84072d75fea0b315407c6c32d68d0e2428184bad56302cc5f920a33b34139b0c27aec13cdd5962d8ff4374788f3f0503..null..0
reconstructed master public key: 88b8aa62727da6ab4a10d077a4e5cfe038695925f037db5b7c91efa824d1b7ad80056083077e592f00142ac6abf208d30e4b962b94e2fc8c759a7c6faab7b2f8718b3a8cb156da061176ddeaefb13a6c3568a9614608bddc67f982a1d710d28e
DEBUG: token is for email: XXXXXXXXXXXXXXXXXXXX
reconstructed token: a412949c279d85583f1a7918e3883e41378562f3127b0d915bd720ddf2f64df72ced2be7941c34409d6c96ce81fb1821 for identity LoI..dic.it..XXXXXXXXXXXXXXXXXXXX..11..2023..null..0
DEBUG: Verification of reconstructed token: success.

In the previous output, for privacy reasons, I replaced my own Social Security Number (SSN) that corresponds to the Italian codice fiscale with the string XXX....X. One can also issue the same command with the option -anon to get a token for the identifier corresponding to the SSN. The difference is that the SSN may usually contain private information. For example in Italy the SSN exposes your birth date and birth place and some characters of your name. Indeed, the Italian SSN is a deterministic function of name, surname, birth date, birth place and you can get the SSN of any Italian citizen if you know such data. Instead, the identifier obtained through the -anon option should be only known to governmental entities so it is somehow more anonymous.

Once you get the token you can issue the commands encrypt.js, decrypt.js, sign.js, verify.js with respect to such token specifying as parameter to the option --email the SSN or the identifier (depending on whether the token was issues without or with the option -anon).

To generalize the functionality to DIC issued by other countries the modifications should be the following. For the Italian DIC there is a folder dic/it containing the Italian local issuer certificates, that is the certificates under which the certificate of an owner of an Italian DIC is signed. For other countries you would just need to create separate folders containing the right local issuer certificates of the country to support. Moreover, the Italian certificate provides in the field commonName a string of the form X/Y where X is the user's SSN and Y is the identifier of such SSN. Each country may have different standards. For example the Italian DIC provides in the serialNumber field the identity number of the DIC itself that can be alternatively used as identity information.

Notes: the current implementation does not check if the signed file was signed by a user whose DIC certificate was revoked. This should be easy to add using the country specific OCSP service. Moreover there are two types of local issuer certificates for Italy and the current implementation assumes that each certificate is signed under only one of them so it will fail when a user certificate is signed by the second local issuer certificate.

Creating DAOs of citizens younger or older than a given age

With the option --age <value> it is possible to require that the token be granted only to citizens that are either born in the year value or after if value is a positive integer of the form XX or born in the year -value if value is a negative integer of the form -XX. Then, if for example we use the option --age 90 (or --age -90) for a user with SSN (or identifier depending on whether the option --anon is not used or is used) equal to Z we should then specify --email 1990@Z (or --email -1990@Z) to the commands encrypt, decrypt, sign, verify. Note that this option is very powerful along with the option --anon. Indeed, in this case the user is identified by an email of the form 1990@Z (or -1990@Z) where Z is somehow anonymous and notwithstanding a smart contract can differentiate the age of the user to create e.g. the DAO of citizens that are born after 1990 (or before). Our formulation of the age information is tailored for the Italian DIC and could be different for other cards.

Cross-country tokens

If the options --cross_country is set, the token is set to to a generic value dic. In this way tokens, ciphertexts and signatures for different countries can be interoperable. You need anyway to specify the full provider (e.g., dic.it) to all commands in order to extract country specific information from the DIC.

About creating the DAO of the citizens of a given town or province

Unfortunately, DICs do not usually contain info like the Town of residency of the citizen. However, a DIC does often store another certificate signed with the citizen's certificate that in turn does contain additional information like the town, street, etc. of residency of the citizen. Therefore, it should be possible to extend the current demo to have the user to send this additional certificate in order to get a token corresponding e.g. to a given town.

Smart contracts

See here for examples of smart contracts using LoI.

TODOs

  • As explained here one can define a token based on e.g. the intersection of Google and Facebook providers. In this way, Google or Facebook alone could not compute tokens on behalf of users. It would be a nice feature to be added.

References

Vincenzo Iovino, Aragon ZK Research. League of Identity: distributed identity-based encryption and authentication from Google and other providers, 2023.