iden3js
Javascript client library of the iden3 system.
Install
npm install --save iden3
https://www.npmjs.com/package/iden3
Basic example
// import iden3jsconst iden3 = ; // new databaseconst db = ;// new key container using localStorageconst kc = 'localStorage' db; // unlock the KeyContainer for the next 30 secondslet passphrase = 'this is a test passphrase';kc; // generate new keyslet keys = kc;/*keys ={ keys: [ '0x94f1d9fdf01abec15ba9c473dbb87f9931986a86', '0xa50970867092c1ae769fc24d5f5151c7b87ff715', '0x1526824c893cb894d18f0cc400c24d96340a4341' ], mnemonic: 'blanket kick genre rubber better helmet youth slush acid select brick setup'}*/let keyRecover = keyskeys0;let keyRevoke = keyskeys1;let keyOp = keyskeys2; // also we can import an already existing seedlet seed = 'blanket kick genre rubber better helmet youth slush acid select brick setup';let keys = kc; // For more info and details about mnemonic, see section Usage>KeyContainer // Also, we have other 2 methods to create keys, kc.importKey and kc.generateKeyRand: // import privkeylet key0id = kc;// key0id is the address of the imported key, will be used as key identifier // generate key randomlet key1id = kc;// key1id is the address of the generated key, will be used as key identifier // create a new relay objectconst relay = 'http://127.0.0.1:5000'; // create a new id objectlet id = keyRecover keyRevoke keyOp relay ''; // create the counterfactoual contract through the relay, get the identity address as responseid; // bind the identity address to a name. Internally, signs the idaddr+name, and sends it to the relay, that will perform an AssignNameClaim vinculating the identity address with the name.id; // generate new key that will be the one authorized by the other keylet ksign = kc; let unixtime = Math;// create new AuthorizeKSignClaim, sign it, and send it to the Relayid; // create new genericClaim, sign it and send it to the Relayid; // having a proof of a leaf, we can check itlet verified = iden3merkleTree;// verified == true // having a proofOfClaim, let's check itlet verified = iden3claim;// verified == true // centralized authentication// once have the QR data scanned, or the hex QR data copiedlet qrJson = iden3auth;let qrKSign = iden3utils;// perform the AuthorizeKSignClaim over the qrKSignid;
Login protocol documentation
https://github.com/iden3/iden3js/blob/master/src/protocols/README.md
Usage
Import
const iden3 = ;
KeyContainer
- new KeyContainer using localStorage// new key containerlet kc = 'localStorage';
Usage:
// unlock the KeyContainerlet passphrase = 'this is a test passphrase';kc; // we can generate a new mnemonic just calling:let keys = kc;/*this returns:keys ={ keys: [ // addresses of the keys '0x94f1d9fdf01abec15ba9c473dbb87f9931986a86', '0xa50970867092c1ae769fc24d5f5151c7b87ff715', '0x1526824c893cb894d18f0cc400c24d96340a4341' ], mnemonic: 'blanket kick genre rubber better helmet youth slush acid select brick setup'}*/ // also we can import an already existing seedlet seed = 'blanket kick genre rubber better helmet youth slush acid select brick setup';let keys = kc; /*And we can specify the diferent identity profiles that we want to derivate from that seed.We can specify which identity profile we want to derivate, and how many keys we want to generate*/ // for example, for our first identity0, we want 4 different keys, so will call the method specifying that we want the identity profile 0, and 4 keys:let keys_id0 = kc;// for the idenity1, we want 2 keys:let keys_id1 = kc;// and for the identity2 we want 5 keys:let keys_id2 = kc; // by default, if we don't specify the path profile and the number of keys, the function returns 3 keys for the path profile 0. // Also, we have other 2 methods to create keys, kc.importKey and kc.generateKeyRand: // import keylet key0id = kc;// key0id is the address of the imported key, will be used as key identifier // generate keylet key1id = kc;// key1id is the address of the generated key, will be used as key identifier // sign using key0idlet signature = kc; // get an array with the address identifiers of the keys stored in the KeyContainerlet keysList = kc;
Id
// new key containerlet kc = ; // unlock the KeyContainer for the next 30 secondslet passphrase = 'this is a test passphrase';kc; // generate new keyslet keyRecover = kc;let keyRevoke = kc;let keyOp = kc; // new relayconst relay = 'http://127.0.0.1:5000';// create keylet id = keyRecover keyRevoke keyOp relay '';
id.createID
Creates the counterfactual contract through the Relay
, and gets the identity address.
id;
Output:
idaddr : '0x46b57a3f315f99a6de39406310f5bd0db03326c1'
id.deployID
Deploys the counterfactual smart contract of identity to the blockchain.
id;
Output:
idaddr: '0x8435ebb41634c05019be1710be0007fa0d92861f' tx: '0x403859ccc701eb358d3a25c908c33de733cbb2d0ebc1c7738eed4908cc8cf5c4'
id.bindID
Vinculates a name to the identity.
Internally, signs the idaddr+name, and sends it to the Relay
, that will perform an AssignNameClaim vinculating the identity address with the name.
id;
Output:
ethAddr: '0xbc8c480e68d0895f1e410f4e4ea6e2d6b160ca9f' name: 'username' signature: '0xeda8b278eae69cd8c4863380f0af5cfe8360481790d8ea5c188705b552bc0d5e1384efb627db5b423d4a163ad02ca23a2f05eea5dc787ac5837789aa95f50f101b'
id.authorizeKSignClaim
// perform a new AuthorizeKSignClaim, sign it, and post it to the Relaylet keyToAuth = kc;id;
id.genericClaim
// perform a new genericClaim, sign it, and post it to the Relayid;
Claims
Generic Claim
// new GenericClaimlet claim = 'iden3.io' 'default' 'extra index data' 'extra data';/*claim:{ baseIndex: { namespace: < Buffer 3 c fc 3 a 1 e db f6 91 31 6 f ec 9 b 75 97 0 f bf b2 b0 e8 d8 ed fc 6 e c7 62 8 d b7 7 c 49 69 40 30 74 > , type: < Buffer cf ee 7 c 08 a9 8 f 4 b 56 5 d 12 4 c 7 e 4 e 28 ac c5 2 e 1 b c7 80 e3 88 7 d b0 > , indexLength: 66, version: 0 }, extraIndex: { data: < Buffer 63 31 > }, data: < Buffer >}*/// methods of the GenericClaimclaim; // claim in Buffer representationclaim; // Hash of the index of the claim in Buffer representationclaim; // Hash of the claim in Buffer representation // parse GenericClaim from Bufferlet claimParsed = iden3claim;
authorizeKSignClaim
// new AuthorizeKSignClaimlet authorizeKSignClaim = '0x101d2fa51f8259df207115af9eaa73f3f4e52e60' 'appToAuthName' 'authz' 1535208350 1535208350;/*authorizeKSignClaim:{ baseIndex: { namespace: < Buffer 3 c fc 3 a 1 e db f6 91 31 6 f ec 9 b 75 97 0 f bf b2 b0 e8 d8 ed fc 6 e c7 62 8 d b7 7 c 49 69 40 30 74 > , type: < Buffer 35 3 f 86 7 e f7 25 41 1 d e0 5 e 3 d 4 b 0 a 01 c3 7 c f7 ad 24 bc c2 13 14 1 a > , indexLength: 84, version: 0 }, extraIndex: { keyToAuthorize: '0x101d2fa51f8259df207115af9eaa73f3f4e52e60' }, application: < Buffer 20 77 bb 3 f 04 00 dd 62 42 1 c 97 22 05 36 fd 6 e d2 be 29 22 8 e 8 d b1 31 5 e 8 c 6 d 75 25 f4 bd f4 > , applicationAuthz: < Buffer da d9 96 6 a 2 e 73 71 f0 a2 4 b 19 29 ed 76 5 c 0 e 7 a 3 f 2 b 46 65 a7 6 a 19 d5 81 73 30 8 b b3 40 62 > , validFrom: 1535208350, validUntil: 1535208350}*/// methods of the AuthorizeKSignClaimauthorizeKSignClaim; // claim in Buffer representationauthorizeKSignClaim; // Hash of the index of the claim in Buffer representationauthorizeKSignClaim; // Hash of the index of the claim in Buffer representation // parse AuthorizeKSignClaim from Bufferlet authorizeKSignClaimParsed = iden3claim;
checkProofOfClaim
This function checks the data structure of proofOfClaim
and returns true if all the proofs are correct.
Internally, it usees the iden3.merkleTree.checkProof()
function, for each one of the proofs that are contained inside proofOfClaim
data object.
Checks the full proof
of a claim
. This means check the:
Merkle Proof
of theclaim
Merkle Proof
of the non revocationclaim
Merkle Proof
of theclaim
that theRelay
have performed over theidentity
Merkle Root
(this kind of claim is theSetRootClaim
)Merkle Proof
of the non revocation of theSetRootClaim
let proofOfClaimStr = `{ "ClaimProof": { "Leaf": "0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c4969403074353f867ef725411de05e3d4b0a01c37cf7ad24bcc213141a0000005400000000970e8128ab834e8eac17ab8e3812f010678cf7912077bb3f0400dd62421c97220536fd6ed2be29228e8db1315e8c6d7525f4bdf4dad9966a2e7371f0a24b1929ed765c0e7a3f2b4665a76a19d58173308bb34062000000005b816b9e000000005b816b9e", "Proof": "0x00000000000000000000000000000000000000000000000000000000000000052d3cbe677b6e4048e0db5a3d550e5f1bb2252c099a990137ac644ddfff9553dde5d128f57df872a6ab1c768ab3da7fc08faa153d4ac40c33471d25be32b38132", "Root": "0xb98333b2c502fc156d0ee7779d77aa9063fcbc6ed41e5c3e8b9900f379523101" }, "SetRootClaimProof": { "Leaf": "0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c49694030749b9a76a0132a0814192c05c9321efc30c7286f6187f18fc60000005400000003bc8c480e68d0895f1e410f4e4ea6e2d6b160ca9fb98333b2c502fc156d0ee7779d77aa9063fcbc6ed41e5c3e8b9900f379523101", "Proof": "0x000000000000000000000000000000000000000000000000000000000000000b7d2ff8e70da77ef7559614425aa33021eb88752f63a690911c031a1fae273f9393b3f57a79800ca02cd1ac3a555d9dbb7d5869251d51d34e01d7de4ab811e9753cb6d37abb4eae8eeea11cbae9a96a021e2d157340721884763fc2ac33313ecd", "Root": "0x33f1e9b3ed86317369938d5bb04ba23e5f5de65da07c3a9368ffe19121e7a6c6" }, "ClaimNonRevocationProof": { "Leaf": "0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c4969403074353f867ef725411de05e3d4b0a01c37cf7ad24bcc213141a0000005400000001970e8128ab834e8eac17ab8e3812f010678cf7912077bb3f0400dd62421c97220536fd6ed2be29228e8db1315e8c6d7525f4bdf4dad9966a2e7371f0a24b1929ed765c0e7a3f2b4665a76a19d58173308bb34062000000005b816b9e000000005b816b9e", "Proof": "0x0000000000000000000000000000000000000000000000000000000000000003df560419165ec6b3299f04ac93510999379987ff25b0799a738ad0d078c9b9d6f912e7e2fab90f745aab5874a5e4f7657921b271378ea05ee9b0f25d69f87a3c", "Root": "0xb98333b2c502fc156d0ee7779d77aa9063fcbc6ed41e5c3e8b9900f379523101" }, "SetRootClaimNonRevocationProof": { "Leaf": "0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c49694030749b9a76a0132a0814192c05c9321efc30c7286f6187f18fc60000005400000004bc8c480e68d0895f1e410f4e4ea6e2d6b160ca9fb98333b2c502fc156d0ee7779d77aa9063fcbc6ed41e5c3e8b9900f379523101", "Proof": "0x000000000000000000000000000000000000000000000000000000000000000b615fadf56023c4ef72c3d455f0e6b6f9ace467e751e9b8e350fe0401368faf4801d4499dba57c843cd6c64fb07975d506e27b5e68166493618405a4bbf2b256eaf677f70fad9050c9d8e77b727fe6d29187c054cd47cfb3fcc10b2a4cbf08f8c", "Root": "0x33f1e9b3ed86317369938d5bb04ba23e5f5de65da07c3a9368ffe19121e7a6c6" }, "Date": 1539008518, "Signature": "0x19074094d44fc77bc020d6c51c2e3f71fb45ede33b05202553d785cfce7d702411b98a4d0980d35383dfbe1d5b9779ee3b8f6295c27969bcf45156cdf6382b6201"}`;let proofOfClaim = JSON;let verified = iden3claim;// verified === true
Merkletree
Merkle tree initialization
Three parameters as an inputs:
- db --> where to store key-value merkle tree nodes
- numLevels --> number of levels of the merkle tree
- idaddr --> used as key prefix at the time to store key nodes
// new databaseconst db = ;// hardcoded id address for multi identity purposesconst idaddr = "";// number of merkle tree levelsconst numLevels = 140;// new merkle tree class instancelet mt = dbnumLevelsidaddr;
Add claim
Add a leaf into the merkle tree. Note the leaf object structure containing data
and indexLength
in order to compute total hash and index hash
// Create data leaf structurelet leaf = data: Buffer indexLength: 15 ; // Add leaf to the merkle treemt;
Get leaf data by hash Index
Look for a index leaf on the merkle tree ans retrieves its data
// compute hash index of the leafconst hashIndex = iden3utils;// retrieve data of the leaflet dataLeaf = mt;
Generate Proof
Generates an array with all the siblings needed in order to proof that a certain leaf is on a merkle tree.
// get leafProof for a given leaf indexconst leafProof = mt;// code `leafProof` into a stringlet leafProofHex = iden3utils;
CheckProof
Checks the Merkle Proof
of a Leaf
.
Proof-of-existence
// retrieve merkle tree root and code it into a stringlet rootHex = iden3utils;// code hash index into a stringlet hashIndexHex = iden3utils;// compute total hash of the leaf and code it into a stringlet hashTotalHex = iden3utils;// check if a leaf is on the merkle treelet verified = iden3merkleTree;
Proof-of-non-existence
Generates leafProof
of a leaf that is not on the merkle tree and check if it is on the merkle tree.
// create leaf data structurelet leaf2 = data: Buffer indexLength: 15 // compute hash indexconst hashIndex2 = iden3utils;// generate leaf proofconst profLeaf2 = mt;// code leaf proof into a stringlet profLeaf2Hex = iden3utils;// code hash index into a stringlet hashIndex2Hex = iden3utils;// compute total hash index and code it into a stringlet hashTotal2Hex = iden3utils; // check if a leaf is on the merkle treelet verifiedRandom = iden3merkleTree;
The complete example can be found in merkle-tree.example.js
.
Utils
// hash Bufferlet hash = iden3utils; let hex = iden3utils; // returns a Hexadecimal representation of a Bufferlet buff = iden3utils; // returns a Buffer from a Heximal representation string // verify signaturelet verified = iden3utils;// verified: true
Relay http
Connectors to interact with the relay API REST.
Create Relay object
const relay = 'http://127.0.0.1:5000';
relay.getRelayRoot
relay ;
Response:
contractRoot: '0x6e4659fedd8ff00b14e487d6d5f537646f07bde944d935d51bd9de807d6fc1c9' root: '0x0000000000000000000000000000000000000000000000000000000000000000'
relay.getIDRoot
relay ;
Response:
idRoot: '0x0000000000000000000000000000000000000000000000000000000000000000' idRootProof: '0x0000000000000000000000000000000000000000000000000000000000000000' root: '0x0000000000000000000000000000000000000000000000000000000000000000'
relay.genericClaim
Creates a new AuthorizeKSignClaim, signs it, and sends it to the Relay.
relay;
relay.authorizeKSignClaim
Creates a new authorizeKSignClaim, signs it, and sends it to the Relay.
relay;
relay.postClaim
Sends to the Relay a signed Claim.
relay ;
The response is the ProofOfClaim
, same as returned in relay.getClaimByHi().
relay.getClaimByHi
relay ;
Response, ProofOfClaim
:
claimProof: Leaf: '0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c4969403074353f867ef725411de05e3d4b0a01c37cf7ad24bcc213141a05ed7726d7932a1f00000000bc8c480e68d0895f1e410f4e4ea6e2d6b160ca9f2077bb3f0400dd62421c97220536fd6ed2be29228e8db1315e8c6d7525f4bdf4dad9966a2e7371f0a24b1929ed765c0e7a3f2b4665a76a19d58173308bb34062000000005b816b9e000000005b816b9e' Hi: '0x438a26007910a723fedf030efd08fed2d374634eb8866ce595c139ea341daa43' Proof: '0x0000000000000000000000000000000000000000000000000000000000000000' Root: '0xd1d3ebd84f46ec73767a2fe89930f33eef96ddf18c35e03faf03a98c8e6bf207' setRootClaimProof: Leaf: '0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c49694030749b9a76a0132a0814192c05c9321efc30c7286f6187f18fc6b6858214fe963e0e00000000bc8c480e68d0895f1e410f4e4ea6e2d6b160ca9fd1d3ebd84f46ec73767a2fe89930f33eef96ddf18c35e03faf03a98c8e6bf207' Hi: '0xbadb12c663dc83678de0709619fb8c67f939b7a2c5c658a6305fa4841e62e392' Proof: '0x0000000000000000000000000000000000000000000000000000000000000000' Root: '0xfd89568c4dfe0b22be91c810421dcf02ac7ca42bc005461886a443fb6e0ead78' claimNonRevocationProof: Leaf: '0x0000000000000000000000000000000000000000000000000000000000000000' Hi: '0x1d4221032dae2392d162cf09030f5ad9fb135380a49bb1e8caf549aaea42b53f' Proof: '0x0000000000000000000000000000000000000000000000000000000000000004ce587b2d039c876de24e8b7fbdeb4cf6b84d542a60cdef47cf0ab29c631fba26' Root: '0xd1d3ebd84f46ec73767a2fe89930f33eef96ddf18c35e03faf03a98c8e6bf207' setRootClaimNonRevocationProof: Leaf: '0x0000000000000000000000000000000000000000000000000000000000000000' Hi: '0x28f5ee91e756ec1a3d1ea9ca2a68b5dde6ded3ea98effeadcefbff9a352aa434' Proof: '0x0000000000000000000000000000000000000000000000000000000000000002b8193081f59feef7baab60cd827267371b2e6495cd2efab189370e0e2ea5819c' Root: '0xfd89568c4dfe0b22be91c810421dcf02ac7ca42bc005461886a443fb6e0ead78'
GET relay.getID
relay ;
Output:
IDAddr: '0x46b57a3f315f99a6de39406310f5bd0db03326c1' LocalDb: Operational: '0x970e8128ab834e8eac17ab8e3812f010678cf791' Relayer: '0xe0fbce58cfaa72812103f003adce3f284fe5fc7c' Recoverer: '0x970e8128ab834e8eac17ab8e3812f010678cf791' Revokator: '0x970e8128ab834e8eac17ab8e3812f010678cf791' Impl: '0x2623ed1533d47d56f912300ae40f83b9370cead6' Onchain: null
relay.resolveName
relay ;
Output:
claim: '0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c4969403074b7ae3d3a2056c54f48763999f3ff99caffaaba3bab58cae900000080000000008a440962fb17f0fe928a3d930137743fe63b8f4c0ce5a5da63991310103d9aef3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c4969403074bc8c480e68d0895f1e410f4e4ea6e2d6b160ca9f' ethAddr: '0xbc8c480e68d0895f1e410f4e4ea6e2d6b160ca9f'
Auth
// once have the QR data scanned, or the hex QR data copiedlet qrJson = iden3auth;let qrKSign = iden3utils;// perform the AuthorizeKSignClaim over the qrKSignid;
Centralized Apps integration
The following instructions are for centralized apps, to integrate the iden3 system for authentication.
Once having a centrauth
backend running ( https://github.com/iden3/go-iden3 ).
Include the iden3js
library:
const iden3 = ;
Or in the html include:
Add in the html the div that will contain the QR:
<!-- and optionally, the textarea to place the qr data in hex format -->
In the js:
let passphrase = 'this is a test passphrase';const authurl = 'http://IPcentrauth:5000';const authwsurl = 'ws://IPcentrauth:5000'; let kc = 'localstorage';kc; let ksign = kc; let auth = kc ksign authurl authwsurl { // callback that will be called when the websocket gets the token, after the backend checks the authentication (challenge, signature, KSign, KSignProof, etc) ; /* authData = { "success": true, "token": "xxxxxxxx" } */};auth; let qrHex = auth; // optional, to show the qr hex datadocumentvalue = qrHex; // optional, to show the qr hex data
Tests
To run all tests, needs to have a running Relay node.
npm test
Browserify bundle
To generate the browserify bundle:
browserify index.js --standalone iden3 > iden3js-bundle.js
WARNING
All code here is experimental and WIP
License
iden3js is part of the iden3 project copyright 2018 0kims association and published with GPL-3 license, please check the LICENSE file for more details.