Kavach is an encryption SDK that allows you to build your trustless, decentralized and fault-tolerant Applications using distributed key shards with threshold cryptography
- 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)
Just use your favorite package manager to add `lighthouse-kavach to your project:
yarn add @lighthouse-web3/kavach
npm i @lighthouse-web3/kavach
This method generates randomized key shards
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) |
Name | Type | Description |
---|---|---|
masterKey | string | 32 byte string or key |
keyShards | {key:string,index:string}[] | key shards |
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);
});
This method recovers the master key from the shards generated
Name | Type | Description |
---|---|---|
keyShard | {key:string,index:string}[] | minimum amount of key required to recover master key |
Name | Type | Description |
---|---|---|
masterKey | string | 32 byte string or key |
error | ErrorValue | null |
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);
});
shard existing Key into shards
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) |
Name | Type | Description |
---|---|---|
isShardable | boolean | return true is the key could be sharded |
keyShards | keyShard[] | shards |
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);
});
Backup key to lighthouse's Node
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 |
Name | Type | Description |
---|---|---|
isSuccess | boolean | return true is saved |
error | ErrorValue | Errors |
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);
});
recover key shards to lighthouse's Node
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 |
Name | Type | Description |
---|---|---|
keyShards | Array<{key:string; index:string}> | key shards recovered fromm nodes |
error | ErrorValue | Errors |
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);
});
Share file Key to address
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 |
Name | Type | Description |
---|---|---|
isSuccess | boolean | return true if successful |
error | ErrorValue | Errors |
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);
});
revoke access to addresses with direct access
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 |
Name | Type | Description |
---|---|---|
isSuccess | boolean | return true if successful |
error | ErrorValue | Errors |
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);
});
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
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) |
Name | Type | Description |
---|---|---|
isSuccess | boolean | return true if successful |
error | ErrorValue | Errors |
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);
});
Get Consensus Message to Sign
Name | Type | Default | Description |
---|---|---|---|
address | string | address of the owner of the key |
Name | Type | Description |
---|---|---|
message | string | return consensus message |
error | ErrorValue | Errors |
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);
});
Get Consensus Message to Sign
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 |
Name | Type | Description |
---|---|---|
JWT | string | return JWT |
refreshToken | string | |
error | ErrorValue | Errors |
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);
});
Transfer Ownership of a Resource
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 |
Name | Type | Description |
---|---|---|
result | string | Result of the ownership transfer |
error | Error | Any error that occurs |
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);
});