iden3js
Javascript client library of the iden3 system.
Install
npm install --save iden3
https://www.npmjs.com/package/iden3
Basic example
const iden3 = require('iden3');
const db = new iden3.Db();
const kc = new iden3.KeyContainer('localStorage', db);
let passphrase = 'this is a test passphrase';
kc.unlock(passphrase);
let keys = kc.generateKeysMnemonic();
let keyRecover = keys.keys[0];
let keyRevoke = keys.keys[1];
let keyOp = keys.keys[2];
let seed = 'blanket kick genre rubber better helmet youth slush acid select brick setup';
let keys = kc.generateKeysMnemonic(seed);
let key0id = kc.importKey('privKHex');
let key1id = kc.generateKeyRand();
const relay = new iden3.Relay('http://127.0.0.1:5000');
let id = new iden3.Id(keyRecover, keyRevoke, keyOp, relay, '');
id.createID().then(res => {
console.log(res);
console.log(id.idaddr);
});
id.bindID(kc, 'username').then(res => {
console.log(res.data);
});
let ksign = kc.generateKeyRand();
let unixtime = Math.round(+new Date()/1000);
id.authorizeKSignClaim(kc, keyOp, ksign, 'appToAuthName', 'authz', unixtime, unixtime).then(res => {
let proofOfKSign = res.data.proofOfClaim;
});
id.genericClaim(kc, ksign, 'iden3.io', 'default', 'extraindex', 'data').then(res => {
let proofOfClaim = res.data.proofOfClaim;
});
let verified = iden3.merkleTree.checkProof(rootHex, mpHex, hiHex, htHex, numLevels);
let verified = iden3.claim.checkProofOfClaim(proofOfClaim, 140);
let qrJson = iden3.auth.parseQRhex(qrHex);
let qrKSign = iden3.utils.addrFromSig(qrJson.challenge, qrJson.signature);
id.authorizeKSignClaim(kc, id.keyOperational, qrKSign, 'appToAuthName', 'authz', unixtimeFrom, unixtimeUntil).then(res => {
let ksignProof = res.data.proofOfClaim;
iden3.auth.resolv(qrJson.url, id.keyOperational, qrJson.challenge, qrJson.signature, qrKSign, ksignProof).then(res => {
console.log('centralized auth success, the website will refresh with the jwt');
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
Login protocol documentation
https://github.com/iden3/iden3js/blob/master/src/protocols/README.md
Usage
Import
const iden3 = require('iden3');
KeyContainer
Usage:
let passphrase = 'this is a test passphrase';
kc.unlock(passphrase);
let keys = kc.generateKeysMnemonic();
let seed = 'blanket kick genre rubber better helmet youth slush acid select brick setup';
let keys = kc.generateKeysMnemonic(seed);
let keys_id0 = kc.generateKeysMnemonic(seed, 0, 4);
let keys_id1 = kc.generateKeysMnemonic(seed, 1, 2);
let keys_id2 = kc.generateKeysMnemonic(seed, 2, 5);
let key0id = kc.importKey('privKHex');
let key1id = kc.generateKeyRandom();
let signature = kc.sign(key0id, 'test');
let keysList = kc.listKeys();
Id
let kc = new iden3.KeyContainer();
let passphrase = 'this is a test passphrase';
kc.unlock(passphrase);
let keyRecover = kc.generateKey();
let keyRevoke = kc.generateKey();
let keyOp = kc.generateKey();
const relay = new iden3.Relay('http://127.0.0.1:5000');
let id = new iden3.Id(keyRecover, keyRevoke, keyOp, relay, '');
id.createID
Creates the counterfactual contract through the Relay
, and gets the identity address.
id.createID().then(res => {
console.log(res);
});
Output:
{
idaddr : '0x46b57a3f315f99a6de39406310f5bd0db03326c1'
}
id.deployID
Deploys the counterfactual smart contract of identity to the blockchain.
id.deployID().then(res => {
console.log(res.data);
});
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.bindID(kc, name).then(res => {
console.log(res.data);
});
Output:
{
ethAddr: '0xbc8c480e68d0895f1e410f4e4ea6e2d6b160ca9f',
name: 'username',
signature: '0xeda8b278eae69cd8c4863380f0af5cfe8360481790d8ea5c188705b552bc0d5e1384efb627db5b423d4a163ad02ca23a2f05eea5dc787ac5837789aa95f50f101b'
}
id.authorizeKSignClaim
let keyToAuth = kc.generateKey();
id.authorizeKSignClaim(kc, key0id, keyToAuth, 'appToAuthName', 'authz', 1535208350, 1535208350).then(res => {
});
id.genericClaim
id.genericClaim(kc, ksign, 'iden3.io', 'default', 'extraindex', 'data').then(res => {
});
Claims
Generic Claim
let claim = new iden3.claim.GenericClaim('iden3.io', 'default', 'extra index data', 'extra data');
claim.bytes();
claim.hi();
claim.ht();
let claimParsed = iden3.claim.parseGenericClaimBytes(claim.bytes());
authorizeKSignClaim
let authorizeKSignClaim = new iden3.claim.AuthorizeKSignClaim('0x101d2fa51f8259df207115af9eaa73f3f4e52e60',
'appToAuthName', 'authz', 1535208350, 1535208350);
authorizeKSignClaim.bytes();
authorizeKSignClaim.hi();
authorizeKSignClaim.ht();
let authorizeKSignClaimParsed = iden3.claim.parseAuthorizeKSignClaim(authorizeKSignClaim.bytes());
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 the claim
Merkle Proof
of the non revocation claim
Merkle Proof
of the claim
that the Relay
have performed over the identity
Merkle Root
(this kind of claim is the SetRootClaim
)Merkle Proof
of the non revocation of the SetRootClaim
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.parse(proofOfClaimStr);
let verified = iden3.claim.checkProofOfClaim(proofOfClaim, 140);
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
const db = new iden3.Db();
const idaddr = "";
const numLevels = 140;
let mt = new iden3.merkleTree.MerkleTree(db,numLevels,idaddr);
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
let leaf = {
data: Buffer.from('this is a test leaf'),
indexLength: 15
};
mt.addClaim(leaf);
Get leaf data by hash Index
Look for a index leaf on the merkle tree ans retrieves its data
const hashIndex = iden3.utils.hashBytes(leaf.data.slice(0, leaf.indexLength));
let dataLeaf = mt.getClaimByHi(hashIndex);
Generate Proof
Generates an array with all the siblings needed in order to proof that a certain leaf is on a merkle tree.
const leafProof = mt.generateProof(hashIndex);
let leafProofHex = iden3.utils.bytesToHex(leafProof);
CheckProof
Checks the Merkle Proof
of a Leaf
.
Proof-of-existence
let rootHex = iden3.utils.bytesToHex(mt.root);
let hashIndexHex = iden3.utils.bytesToHex(hashIndex);
let hashTotalHex = iden3.utils.bytesToHex(iden3.utils.hashBytes(leaf.data));
let verified = iden3.merkleTree.checkProof(rootHex, leafProofHex, hashIndexHex, hashTotalHex, 140);
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.
let leaf2 = {
data: Buffer.from('this is a second test leaf'),
indexLength: 15
}
const hashIndex2 = iden3.utils.hashBytes(leaf2.data.slice(0, leaf2.indexLength));
const profLeaf2 = mt.generateProof(hashIndex2);
let profLeaf2Hex = iden3.utils.bytesToHex(profLeaf2);
let hashIndex2Hex = iden3.utils.bytesToHex(hashIndex2);
let hashTotal2Hex = iden3.utils.bytesToHex(iden3.utils.hashBytes(leaf2.data));
let verifiedRandom = iden3.merkleTree.checkProof(rootHex, profLeaf2Hex, hashIndex2Hex, hashTotal2Hex, 140);
The complete example can be found in merkle-tree.example.js
.
Utils
let hash = iden3.utils.hashBytes(b);
let hex = iden3.utils.bytesToHex(buff);
let buff = iden3.utils.hexToBytes(hex);
let verified = iden3.utils.verifySignature(msgHashHex, signatureHex, addressHex);
Relay http
Connectors to interact with the relay API REST.
Create Relay object
const relay = new iden3.Relay('http://127.0.0.1:5000');
relay.getRelayRoot
relay.getRelayRoot()
.then(res => {
console.log('res.data', res.data);
});
Response:
{
contractRoot: '0x6e4659fedd8ff00b14e487d6d5f537646f07bde944d935d51bd9de807d6fc1c9',
root: '0x0000000000000000000000000000000000000000000000000000000000000000'
}
relay.getIDRoot
relay.getIDRoot(id.kc.addressHex())
.then(res => {
console.log('res.data', res.data);
});
Response:
{
idRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
idRootProof: '0x0000000000000000000000000000000000000000000000000000000000000000',
root: '0x0000000000000000000000000000000000000000000000000000000000000000'
}
relay.genericClaim
Creates a new AuthorizeKSignClaim, signs it, and sends it to the Relay.
relay.genericClaim(id.kc, ksign, 'iden3.io', 'default', 'data of the claim').then(res => {
expect(res.status).to.be.equal(200);
});
relay.authorizeKSignClaim
Creates a new authorizeKSignClaim, signs it, and sends it to the Relay.
relay.authorizeKSignClaim(id.kc, keyid, kSign.addressHex(), 'appToAuthName', 'authz', 1535208350, 1535208350).then(res => {
expect(res.status).to.be.equal(200);
});
relay.postClaim
Sends to the Relay a signed Claim.
relay.postClaim(idaddr, bytesSignedMsg)
.then(res => {
console.log('res.data', res.data);
});
The response is the ProofOfClaim
, same as returned in relay.getClaimByHi().
relay.getClaimByHi
relay.getClaimByHi(idaddr, hi)
.then(res => {
console.log('res.data', res.data);
});
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.getID('0x46b57a3f315f99a6de39406310f5bd0db03326c1')
.then(res => {
console.log('res.data', res.data);
});
Output:
{
IDAddr: '0x46b57a3f315f99a6de39406310f5bd0db03326c1',
LocalDb: {
Operational: '0x970e8128ab834e8eac17ab8e3812f010678cf791',
Relayer: '0xe0fbce58cfaa72812103f003adce3f284fe5fc7c',
Recoverer: '0x970e8128ab834e8eac17ab8e3812f010678cf791',
Revokator: '0x970e8128ab834e8eac17ab8e3812f010678cf791',
Impl: '0x2623ed1533d47d56f912300ae40f83b9370cead6'
},
Onchain: null
}
relay.resolveName
relay.resolveName('username@iden3.io')
.then(res => {
console.log('res.data', res.data);
});
Output:
{
claim: '0x3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c4969403074b7ae3d3a2056c54f48763999f3ff99caffaaba3bab58cae900000080000000008a440962fb17f0fe928a3d930137743fe63b8f4c0ce5a5da63991310103d9aef3cfc3a1edbf691316fec9b75970fbfb2b0e8d8edfc6ec7628db77c4969403074bc8c480e68d0895f1e410f4e4ea6e2d6b160ca9f',
ethAddr: '0xbc8c480e68d0895f1e410f4e4ea6e2d6b160ca9f'
}
Auth
let qrJson = iden3.auth.parseQRhex(qrHex);
let qrKSign = iden3.utils.addrFromSig(qrJson.challenge, qrJson.signature);
id.authorizeKSignClaim(kc, id.keyOperational, qrKSign, 'appToAuthName', 'authz', unixtimeFrom, unixtimeUntil).then(res => {
let ksignProof = res.data.proofOfClaim;
iden3.auth.resolv(qrJson.url, id.keyOperational, qrJson.challenge, qrJson.signature, qrKSign, ksignProof).then(res => {
alert('centralized auth success, the website will refresh with the jwt');
})
.catch(function (error) {
alert(error);
});
})
.catch(function (error) {
alert(error);
});
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 = require('iden3');
Or in the html include:
<script src="iden3js-bundle.js"></script>
Add in the html the div that will contain the QR:
<div id="qrcodediv"></div>
<textarea id="qrHex" rows="4" cols="30" readonly="readonly"></textarea>
In the js:
let passphrase = 'this is a test passphrase';
const authurl = 'http://IPcentrauth:5000';
const authwsurl = 'ws://IPcentrauth:5000';
let kc = new iden3.KeyContainer('localstorage');
kc.unlock(passphrase);
let ksign = kc.generateKey();
let auth = new iden3.Auth(kc, ksign, authurl, authwsurl, function(authData) {
alert('✔️ Logged in');
});
auth.printQr('qrcodediv');
let qrHex = auth.qrHex();
document.getElementById("qrHex").value = qrHex;
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.