UNPKG

lighthouse-encryption-sdk-browser

Version:

Encryption SDK: Build your trustless, decentralized and fault resistance Application using distributed key shades with threshold cryptography

806 lines (639 loc) 26.4 kB
# Kavach <img src="https://img.shields.io/badge/BETA-v0.1.6-green"/> Kavach is an encryption SDK that allows you to build your trustless, decentralized and fault-tolerant Applications using distributed key shards with threshold cryptography ## Features - Randomized key shard generation - Shard Key support for privateKey and other security keys - Key Reconstruction from shards - Fully typed, support in TypeScript - Lighthouse Encryption Key storage(Optional 5 nodes) ## Install Just use your favorite package manager to add `lighthouse-kavach to your project: ```sh yarn add @lighthouse-web3/kavach npm i @lighthouse-web3/kavach ``` ## Methods - ### _generate ( threshold?: number, keyCount?: number)_ This method generates randomized key shards #### Parameters | Name | Type | Default | Description | | --------- | ---------------- | ------- | ----------------------------------------------------------------------------------------- | | threshold | number(optional) | 3 | minimum amount of key required to recover master key | | keyCount | number(optional) | 5 | number of shades to be generated (**Note**: _must be greater than or equal to threshold_) | #### returns | Name | Type | Description | | --------- | --------------------------- | ---------------------- | | masterKey | string | 32 byte string or key | | keyShards | {key:string,index:string}[] | key shards | #### Demo ```javascript import { generate } from "@lighthouse-web3/kavach"; async function main() { const { masterKey, keyShards } = await generate(); console.log(`masterKey: ${masterKey}`); console.log(`keyShards:`, keyShards); } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _recoverKey (keyShards: keyShard[])_ This method recovers the master key from the shards generated #### Parameters | Name | Type | Description | | -------- | --------------------------- | ---------------------------------------------------- | | keyShard | {key:string,index:string}[] | minimum amount of key required to recover master key | #### returns | Name | Type | Description | | --------- | ---------- | --------------------- | | masterKey | string | 32 byte string or key | | error | ErrorValue | null | #### Demo ```javascript import { generate, recoverKey } from "@lighthouse-web3/kavach"; async function main() { const { masterKey, keyShards } = await generate(); const { masterKey: recoveredKey } = await recoverKey(keyShards); console.log(masterKey === recoveredKey); //true } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _shardKey (key: string,threshold?: number, keyCount?: number)_ shard existing Key into shards #### Parameters | Name | Type | Default | Description | | --------- | ---------------- | ------- | ----------------------------------------------------------------------------------------- | | key | string | | 32 byte string or key | | threshold | number(optional) | 3 | minimum amount of key required to recover master key | | keyCount | number(optional) | 5 | number of shades to be generated (**Note**: _must be greater than or equal to threshold_) | #### returns | Name | Type | Description | | ----------- | ---------- | --------------------------------------- | | isShardable | boolean | return true is the key could be sharded | | keyShards | keyShard[] | shards | #### Demo ```javascript import { shardKey, recoverKey } from "@lighthouse-web3/kavach"; async function main() { // known key customly generated or from ether random wallet privateKey // Note: Not all keys are shardable const knownKey = "554f886019b74852ab679258eb3cddf72f12f84dd6a946f8afc4283e48cc9467"; const { isShardable, keyShards } = await shardKey(knownKey); console.log(isShardable); // true //recover keys from shards const { masterKey } = await recoverKey(keyShards); //check if the key recovered was recovered console.log(masterKey === knownKey); //true } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _saveShards( address: string, cid: string, auth_token: string, keyShards: keyShard[5] | any[5], shareTo : string[])_ Backup key to lighthouse's Node #### Parameters | Name | Type | Default | Description | | ----------------- | --------------------------------- | ------- | --------------------------------------------- | | address | string | | address of the owner of the key | | cid | string | | unique id or file CID | | auth_token | string | | signed Message gotten from getAuthMessage/JWT | | keyShards | Array<{key:string; index:string}> | | An array of 5 key shards/ element | | shareTo | Array< address >(Optional) | [] | An array of address | #### returns | Name | Type | Description | | --------- | ---------- | -------------------- | | isSuccess | boolean | return true is saved | | error | ErrorValue | Errors | #### Demo ```javascript import { getAuthMessage, saveShards, generate } from "@lighthouse-web3/kavach"; import { ethers } from "ethers"; async function main() { const signer = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c8b" ); const { masterKey, keyShards } = await generate(); const authMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { error, isSuccess } = await saveShards( signer.address, "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH", signedMessage, keyShards ); console.log(error === null); // true; console.log(isSuccess === true); //true; } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _recoverShards( address: string, cid: string, auth_token: string, dynamicData:{},)_ recover key shards to lighthouse's Node #### Parameters | Name | Type | Default | Description | | ----------------- | ------------------------------------------------------------ | ------- | --------------------------------------------- | | address | string | | address of the owner of the key | | cid | string | | unique id or file CID | | auth_token | string | | signed Message gotten from getAuthMessage/JWT | | keyCount | number(optional) | 3 | number of nodes to ping for shards (**Note**: _must be less than or equal to 5_) | | dynamicData | object<{[`conditionID`.`parameterName`]: value} >(Optional) | {} | This is used to pass additional or dynamic data like a signature during key recovery with AccessControl | #### returns | Name | Type | Description | | ---------------- | ---------------------------------- | ----------------------------------| | keyShards | Array<{key:string; index:string}> | key shards recovered fromm nodes | | error | ErrorValue | Errors | #### Demo ```javascript import { getAuthMessage, saveShards, generate, recoverShards } from "@lighthouse-web3/kavach"; import { ethers } from "ethers"; async function main() { const signer = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c8b" ); const { masterKey, keyShards } = await generate(); let authMessage = await getAuthMessage(signer.address); let signedMessage = await signer.signMessage(authMessage.message); const { error, isSuccess } = await saveShards( signer.address, "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH", signedMessage, keyShards ); console.log(error === null); // true; console.log(isSuccess === true); //true; authMessage = await getAuthMessage(signer.address); signedMessage = await signer.signMessage(authMessage.message); //retrieve 3 keys const { error, shards } = await recoverShards( signer.address, cid, signedMessage, 3 ); console.log(error == null); //true; console.log(shards.length === 3); // true; const { masterKey: recoveredKey } = await recoverKey(shards); console.log(masterKey === recoveredKey); //true } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _shareToAddress(address: string, cid: string, auth_token: string, shareTo: Array<string> )_ Share file Key to address #### Parameters | Name | Type | Default | Description | | ----------------- | ------------------------- | ------- | ----------------------------------------------- | | address | string | | address of the owner of the key | | cid | string | | unique id or file CID | | auth_token | string | | signed Message gotten from getAuthMessage/ JWT | | shareTo | Array< address >(Optional)| [] | An array of address to share file key shards to | #### returns | Name | Type | Description | | --------- | ---------- | ------------------------- | | isSuccess | boolean | return true if successful | | error | ErrorValue | Errors | #### Demo ```javascript import { recoverShards, getAuthMessage, saveShards, AuthMessage, shareToAddress, generate, } from "@lighthouse-web3/kavach"; import { ethers } from "ethers"; async function main() { let signer = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c8b" ); let signer2 = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c99" ); const cid = "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwAV"; const { masterKey, keyShards } = await generate(); //save file { const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { error, isSuccess } = await saveShards( signer.address, cid, signedMessage, keyShards ); console.log(error == null); //true; console.log(isSuccess == true); //true; } //share file key to address address { const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { error, isSuccess } = await shareToAddress( signer.address, cid, signedMessage, [signer2.address] ); console.log(error == null); // true; console.log(isSuccess == true); //true; } //recover shared from address shared to { const authMessage: AuthMessage = await getAuthMessage(signer2.address); const signedMessage = await signer2.signMessage(authMessage.message); //retrieve 3 keys const { error, shards } = await recoverShards( signer2.address, cid, signedMessage, 3 ); console.log(error == null); //true; console.log(shards.length === 3); // true; } } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _revokeAccess(address: string, cid: string, auth_token: string, revokeTo: Array<string> )_ revoke access to addresses with direct access #### Parameters | Name | Type | Default | Description | | ----------------- | ------------------------- | ------- | ----------------------------------------------- | | address | string | | address of the owner of the key | | cid | string | | unique id or file CID | | auth_token | string | | signed Message gotten from getAuthMessage /JWT | | revokeTo | Array< address >(Optional)| [] | An array of address to remove for Direct access | #### returns | Name | Type | Description | | --------- | ---------- | ------------------------- | | isSuccess | boolean | return true if successful | | error | ErrorValue | Errors | #### Demo ```javascript import { recoverShards, getAuthMessage, saveShards, AuthMessage, revokeAccess, generate, } from "@lighthouse-web3/kavach"; import { ethers } from "ethers"; async function main() { let signer = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c8b" ); let signer2 = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c99" ); const cid = "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwVV"; const { masterKey, keyShards } = await generate(); //save file { const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { error, isSuccess } = await saveShards( signer.address, cid, signedMessage, keyShards, [ "0x95CF5354519a6ad2bD7e53fe7763201dfB24bFE4", "0xb46D27B3BfC07D27702EBddbe197Fc9276b70581", signer2.address, ] ); console.log(error == null); //true; console.log(isSuccess == true); //true; } //recover shared from address shared to { const authMessage: AuthMessage = await getAuthMessage(signer2.address); const signedMessage = await signer2.signMessage(authMessage.message); //retrieve 3 keys const { error, shards } = await recoverShards( signer2.address, cid, signedMessage, 3 ); console.log(error == null); //true; console.log(shards.length === 3); // true; } //revoke access to direct shared address { const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { error, isSuccess } = await revokeAccess( signer.address, cid, signedMessage, [signer2.address] ); console.log(error == null); // true; console.log(isSuccess == true); //true; } //recover shared from address shared to { const authMessage: AuthMessage = await getAuthMessage(signer2.address); const signedMessage = await signer2.signMessage(authMessage.message); //retrieve 3 keys const { error, shards } = await recoverShards( signer2.address, cid, signedMessage, 3 ); console.log(error); // { message: "you don't have access", data: {} }; console.log(shards.length === 0); // true ; } } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _accessCondition( address: string, cid: string, auth_token: string, conditions: Condition[], aggregator?: string,chainType?: ChainType, keyShards? : Array<{key:string; index:string}>, decryptionType? : string )_ Add more granular access Conditions based on on-Chain Data, this supports custom EVM contracts, block timestamps and so on. with support for over 15 Ethereum Virtual Machine (EVM) based networks and based Solana RPC calls - Ethereum - Rinkeby - Polygon - Fantom - FantomTest - AVAX - Fuji - BSC - BSCTest - Optimism - OptimismGoerli - OptimismKovan - Mumbai - FVM - Wallaby - Calibration - Shardeum - Goerli - Hyperspace - BTTC - BTTC_Testnet - Sepolia_PGN - Arbitrum_Sepolia - Sepolia: - BASE_Goerli Solana - DEVNET - TESTNET - MAINNET #### Parameters | Name | Type | Description | | ----------------- | ----------------------------------- | ------------------------------------------------------------------------------- | | address | string | Address of the owner of the key | | cid | string | Unique id or file CID | | auth_token | string | Signed Message gotten from getAuthMessage /JWT | | conditions | Array< Condition > | This Array contains a list of conditions to be tested on chain | | aggregator | string | This is a template string that structures how the conditions should be computed | | chainType | string | This defaults to EVM and can be set to Solana for Solana conditions | | keyShards? | Array<{key:string; index:string}> | This Field is optional, you can use it to set, overWrite or rotate key shards | | decryptionType? | string | This value can be set to ACCESS_CONDITIONS to first time shard is added, **WARNING: This sets Owner to address zero(0x0000000000000000000000000000)** | #### returns | Name | Type | Description | | --------- | ---------- | ------------------------- | | isSuccess | boolean | return true if successful | | error | ErrorValue | Errors | #### Demo ```javascript import { recoverShards, getAuthMessage, saveShards, AuthMessage, accessControl, generate, } from "@lighthouse-web3/kavach"; import { ethers } from "ethers"; async function main() { let signer = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c8b" ); let signer2 = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c99" ); const cid = "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwVM"; //save file { const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { masterKey, keyShards } = await generate(); const { error, isSuccess } = await saveShards( signer.address, cid, signedMessage, keyShards ); console.log(error == null); //true; console.log(isSuccess == true); //true; } // add access control to cid direct shared address { const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { error, isSuccess } = await accessControl( signer.address, cid, signedMessage, [ { id: 3, chain: "Polygon", method: "getBlockNumber", standardContractType: "", returnValueTest: { comparator: ">=", value: "0" }, }, { id: 2, chain: "Optimism", method: "getBalance", standardContractType: "", returnValueTest: { comparator: ">=", value: "0" }, }, { id: 1, chain: "FantomTest", method: "balanceOf", standardContractType: "ERC20", contractAddress: "0xF0Bc72fA04aea04d04b1fA80B359Adb566E1c8B1", returnValueTest: { comparator: ">=", value: "0" }, parameters: [":userAddress"], }, ], "([2] and [1]) or [3]" ); console.log(error == null); console.log(isSuccess == true); } // recover shared from an address that matches the above condition // that is // has a balance equal to or greater than Zero on the Optimism mainnet and has a token balance greater than equal to zero of the token 0xF0Bc72fA04aea04d04b1fA80B359Adb566E1c8B1 on fantom's testnet // or if block height is greater than zero { const authMessage: AuthMessage = await getAuthMessage(signer2.address); const signedMessage = await signer2.signMessage(authMessage.message); console.log(signer2.address); //retrieve 3 keys const { error, shards } = await recoverShards( signer2.address, cid, signedMessage, 3, dynamicData ); console.log(error == null); //true; console.log(shards.length === 3); // true; } } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` ## Auth Methods - ### _getAuthMessage( address: string)_ Get Consensus Message to Sign #### Parameters | Name | Type | Default | Description | | ------- | ------ | ------- | ------------------------------- | | address | string | | address of the owner of the key | #### returns | Name | Type | Description | | ------- | ---------- | ------------------------ | | message | string | return consensus message | | error | ErrorValue | Errors | ```javascript import { getAuthMessage, AuthMessage } from "@lighthouse-web3/kavach"; import { ethers } from "ethers"; async function main() { let signer = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c8b" ); // get consensus message const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); console.log(typeof authMessage.message == "string"); //true; console.log(authMessage.error == null); //true; } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _getJWT(address:string,signedMessage: SignedMessage)_ Get Consensus Message to Sign #### Parameters | Name | Type | Default | Description | | ------------------ | ------- | ------- | ---------------------------------------------------- | | address | string | | address of the owner of the key | | payload | string | | signed consensus message or refresh Token | | useAsRefreshToken | boolean | false | If payload is refreshToken this should be set to true | #### returns | Name | Type | Description | | ----------------| ---------- | ----------- | | JWT | string | return JWT | | refreshToken | string | | | error | ErrorValue | Errors | ```javascript import { getAuthMessage, AuthMessage, getJWT } from "@lighthouse-web3/kavach"; import { ethers } from "ethers"; async function main() { let signer = new ethers.Wallet( "0x8218aa5dbf4dbec243142286b93e26af521b3e91219583595a06a7765abc9c8b" ); // get consensus message const authMessage: AuthMessage = await getAuthMessage(signer.address); const signedMessage = await signer.signMessage(authMessage.message); const { JWT, error } = await getJWT(signer.address, signedMessage); console.log(typeof JWT == "string"); //true; console.log(error == null); //true; } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` - ### _transferOwnership(address: string, cid: string, newOwner: string, auth_token: string, resetSharedTo: boolean = true)_ Transfer Ownership of a Resource #### Parameters | Name | Type | Default | Description | | ---------------- | ------- | ------- | ------------------------------------------------ | | address | string | | Address of the current owner of the resource | | cid | string | | Content ID (CID) of the resource | | newOwner | string | | Address of the new owner for the resource | | auth_token | string | | Authentication payload or token | | resetSharedTo | boolean | true | Reset shared permissions when ownership changes | #### Returns | Name | Type | Description | | ---------- | ------ | --------------------------------- | | result | string | Result of the ownership transfer | | error | Error | Any error that occurs | #### Example ```javascript import { transferOwnership } from "@lighthouse-web3/kavach"; // Example usage of transferOwnership function async function main() { const currentOwner = "0x1234567890abcdef"; const resourceId = "QmXyZAbCdEfGhIjK"; const newOwner = "0x9876543210fedcba"; const authPayload = "your-authentication-token"; const { result, error } = await transferOwnership( currentOwner, resourceId, newOwner, authPayload ); if (error) { console.error("Error:", error); } else { console.log("Ownership transfer result:", result); } } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ```