Exporting a Wrapped Key
This guide covers the exportPrivateKey
function from the Wrapped Keys SDK. For an overview of what a Wrapped Key is and what can be done with it, please go here.
Using the exportPrivateKey
function, you can export existing Wrapped Keys to decrypt and obtain their underlying private keys. The Wrapped Keys SDK will look up the corresponding encryption metadata (ciphertext
and dataToEncryptHash
) for your PKP in Lit's private DynamoDB instance. If found, it well then use your provided PKP Session Signatures to authorize decryption of the private key, and will return it to you in clear text.
Below we will walk through an implementation of exportPrivateKey
. The full code implementation can be found here.
Prerequisites
Before continuing with this guide, you should have an understanding of:
exportPrivateKey
's Interface
/** Exports a previously persisted private key from the wrapped keys service for direct use by the caller, along with the keys metadata
*/
export async function exportPrivateKey(
params: {
pkpSessionSigs: SessionSigsMap;
litNodeClient: ILitNodeClient;
}
): Promise<{
pkpAddress: string;
decryptedPrivateKey: string;
publicKey: string;
litNetwork: LIT_NETWORKS_KEYS;
keyType: string;
}>
Parameters
pkpSessionSigs
When a Wrapped Key is generated, it's encrypted with the following Access Control Conditions:
[
{
contractAddress: '',
standardContractType: '',
chain: CHAIN_ETHEREUM,
method: '',
parameters: [':userAddress'],
returnValueTest: {
comparator: '=',
value: pkpAddress,
},
},
];
where pkpAddress
is the addressed derived from the pkpSessionSigs
. This restricts the decryption of the Wrapped Key to only those whom can generate valid Authentication Signatures from the PKP which generated the Wrapped Key.
A valid pkpSessionSigs
object can be obtained using the getPkpSessionSigs helper method available on an instance of LitNodeClient. We dive deeper into obtaining a pkpSessionSigs
using getPkpSessionSigs
in the Generating PKP Session Signatures section of this guide.
litNodeClient
This is an instance of the LitNodeClient that is connected to a Lit network.
Return Value
pkpAddress
This is the Ethereum address for the PKP that is associated with the Wrapped Key i.e. the PKP that created the Session Signatures when the Wrapped Key was imported/generated, and used for encrypting the private key. The address is derived from the provided pkpSessionSigs
.
decryptedPrivateKey
This return value is the private key unencrypted and clear text.
Be mindful when and where you're calling this method as to not expose the private key to anyone who should not have direct access to it.
This is the underlying private key for the Wrapped Key that was either imported into the Lit network, or generated by a Wrapped Keys Lit Action.
publicKey
This is the corresponding public key for the wrapped private key that was either imported into the Lit network, or generated by a Wrapped Keys Lit Action.
litNetwork
This is the Lit network that the LitNodeClient
was connected to when the Wrapped Key was created.
keyType
This is the algorithm used to generate the underlying private key for the Wrapped Key.
Example Implementation
Now that we know what the exportPrivateKey
function does, it's parameters, and it's return values, let's now dig into a complete implementation.
The full code implementation can be found here.
Installing the Required Dependencies
- npm
- yarn
npm install \
@lit-protocol/auth-helpers \
@lit-protocol/constants \
@lit-protocol/lit-auth-client \
@lit-protocol/lit-node-client \
@lit-protocol/wrapped-keys \
ethers@v5
yarn add \
@lit-protocol/auth-helpers \
@lit-protocol/constants \
@lit-protocol/lit-auth-client \
@lit-protocol/lit-node-client \
@lit-protocol/wrapped-keys \
ethers@v5
Instantiating an Ethers Signer
The ETHEREUM_PRIVATE_KEY
environment variable is required. The corresponding Ethereum address needs to have ownership of the PKP we will be using to generate the pkpSessionSigs
.
import * as ethers from 'ethers';
const ethersSigner = new ethers.Wallet(
process.env.ETHEREUM_PRIVATE_KEY,
new ethers.providers.JsonRpcProvider(
"https://chain-rpc.litprotocol.com/http"
)
);
Instantiating a LitNodeClient
Here we are instantiating an instance of LitNodeClient
and connecting it to the cayenne
Lit network.
import { LitNodeClient } from "@lit-protocol/lit-node-client";
import { LitNetwork } from "@lit-protocol/constants";
const litNodeClient = new LitNodeClient({
litNetwork: LitNetwork.Cayenne,
debug: false,
});
await litNodeClient.connect();
Generating PKP Session Signatures
The LIT_PKP_PUBLIC_KEY
environment variable is required. This PKP should be owned by the corresponding Ethereum address for the ETHEREUM_PRIVATE_KEY
environment variable.
The PKP's Ethereum address will be used for the Access Control Conditions used to encrypt the generated private key, and by default, will be the only entity able to authorize decryption of the private key.
The expiration
used for the Auth Method must be 10 minutes or less to be valid.
The Auth Method used in this example implementation is signing a Sign in With Ethereum (EIP-4361) message using an Externally Owned Account (EOA), but any Auth Method can be used to authenticate with Lit to get PKP Session Signatures.
import { EthWalletProvider } from "@lit-protocol/lit-auth-client";
import {
LitAbility,
LitActionResource,
LitPKPResource,
} from "@lit-protocol/auth-helpers";
const pkpSessionSigs = await litNodeClient.getPkpSessionSigs({
pkpPublicKey: process.env.LIT_PKP_PUBLIC_KEY,
authMethods: [
await EthWalletProvider.authenticate({
signer: ethersSigner,
litNodeClient,
expiration: new Date(Date.now() + 1000 * 60 * 10).toISOString(), // 10 minutes
}),
],
resourceAbilityRequests: [
{
resource: new LitActionResource("*"),
ability: LitAbility.LitActionExecution,
},
],
expiration: new Date(Date.now() + 1000 * 60 * 10).toISOString(), // 10 minutes
});
Exporting a Wrapped Key
The return value from successfully calling exportPrivateKey
includes the unencrypted private key in clear text.
Be mindful when and where you're calling this method as to not expose the private key to anyone who should not have direct access to it.
Now that we have all that we need, we can call exportPrivateKey
to export the underlying private key for the Wrapped Key:
import { api } from "@lit-protocol/wrapped-keys";
const { exportPrivateKey } = api;
const exportedPrivateKeyResult = await exportPrivateKey({
pkpSessionSigs,
litNodeClient,
});
Summary
The full code implementation can be found here.
After executing the example implementation above, you will have exported the underlying private key for the Wrapped Key associated with the PKP that produced the provided pkpSessionSigs
.