Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decrypt and Combine Rework #336

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 62 additions & 86 deletions docs/sdk/serverless-signing/combining-decryption-shares.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,99 +4,75 @@ import FeedbackComponent from "@site/src/pages/feedback.md";

## Overview

Decryption with Lit is typically performed client-side by an authorized user at the time of access. This process is documented [here](../access-control/quick-start.md). However, an alternative method of decryption is supported using Lit Actions. Specifically, the `decryptAndCombine` function can be used to decrypt data within a Lit Action. This is useful for performing operations over sensitive data, where the data itself remains private within the confines of each Lit node's Trusted Execution Environment (TEE). You can learn more about Lit's architecture [here](../../resources/how-it-works#sealed-and-confidential-hardware.md).

When you call `decryptAndCombine`, each Lit node's decryption shares are collected and combined on a single node and used to decrypt the given content.

The following doc will provide a complete walkthrough of using `decryptAndCombine`. We'll start by encrypting a string client-side before using a Lit Action to decrypt it. At the bottom of the page you'll find a complete example that demonstrates how you can use this functionality to decrypt an API key and perform a remote API call from within an Action.

# Encrypting content
The first step is to encrypt your data. The encryption operation will be performed client-side *outside* of your Lit Action using the `LitNodeClient`:

```js
const chain = 'ethereum';
const accessControlConditions = [
{
contractAddress: '',
standardContractType: '',
chain,
method: 'eth_getBalance',
parameters: [':userAddress', 'latest'],
returnValueTest: {
comparator: '>=',
value: '0',
},
},
];
const message = 'Hello world';
const client = new LitNodeClient({
litNetwork: "datil-dev"
});
await client.connect();
const { ciphertext, dataToEncryptHash } = await LitJsSdk.encryptString(
{
accessControlConditions,
sessionSigs: {}, // your session
chain,
dataToEncrypt: message,
},
client
);

console.log("cipher text:", ciphertext, "hash:", dataToEncryptHash);
```
Let's break this down. The first step was creating your Access Control Condition (ACC), which is used to specify who or under what conditions your data should be able to be decrypted.

The second step was actually encrypting the static content (string, file, zip, etc...) using the `encryptString` function. This returns a `ciphertext` and `dataToEncryptHash`. The `ciphertext`, `dataToEncryptHash`, chain data, and any other metadata (such as your `accessControlConditions`) should be stored on your storage provider of choice. A solid choice is IPFS.

## Using IPFS CID as an Access Control Parameter
For this example, you can set your Access Control parameter as `currentActionIpfsId` which can be accomplished using the snippet below. This will mean that only a specific Lit Action (based on the IPFS CID where it has been deployed) will be able to decrypt your data. No other party will ever have access. This is useful for situations where you want to restrict access to sensitive information, like an API key, so that it can only be decrypted by a specific Lit Action.

```js
{
contractAddress: '',
standardContractType: '',
chain: 'ethereum',
method: '',
parameters: [':currentActionIpfsId'],
returnValueTest: {
comparator: '=',
value: '<YOUR_LIT_ACTION_IPFS_CID>',
},
}
```
Decryption with Lit can be performed either client-side by an authorized user or within a Lit Action.

Using decryption within a Lit Action is useful for performing operations over sensitive data, where the data itself remains private within the confines of each Lit node's Trusted Execution Environment (TEE). You can learn more about Lit's architecture [here](../../resources/how-it-works#sealed-and-confidential-hardware.md).

Lit Actions have two methods for decrypting data: `decryptToSingleNode` and `decryptAndCombine`. The former reduces the execution scope of the Lit Action to a single node and decrypts the data there. The latter collects each Lit node's decryption share, combines them, and then decrypts the data on a single node. The key difference between the two is that `decryptToSingleNode` only uses the decryption share of a single Lit node, while `decryptAndCombine` uses all of the decryption shares of all Lit nodes.
spacesailor24 marked this conversation as resolved.
Show resolved Hide resolved

When `decryptToSingleNode` is used, the execution scope being reduced to a single Lit node means that any behavior that requires multiple nodes (i.e. console logs, `signAndCombineEcdsa`) will encounter a timeout error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say console logs, do you mean console.log? I don't think there's an affect on these when running within a single node?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a snippet on how to end execution on all the Lit node that weren't selected for the decryption

That looks something like this


## Using decryptAndCombine
The following example demonstrates how to encrypt an API key client-side, then decrypt and use it within a Lit Action to query the block number on Base.

We can now use the `ciphertext` and `dataToEncryptHash` that we got earlier during the encryption step and pass it into our Lit Action.
## Prerequsites
- Knowledge of [SessionSigs](../authentication/session-sigs/intro)
- Basic understanding of [Lit Actions](../serverless-signing/quick-start)
- Intermediate understanding of Lit [Encryption and Decryption](../access-control/quick-start)

In the below example we set the `authSig` to `null` as a way to tell the Lit Action runtime to use the `authSig` which was provided to the node when you call `executeJs` which returns `sessionSigs`. If you wish you may provide a different Auth Signature if the one provided from the session is not relevant to your use case. You can learn more about authentication and creating session signatures using these [docs](../authentication/session-sigs/intro.md).
## Complete Code Example
The complete code example is available in the [Lit Developer Guides Code Repository](https://github.com/LIT-Protocol/developer-guides-code/tree/master/decrypt-api-key-in-action/nodejs).

```js
const code = `(async () => {
const resp = await Lit.Actions.decryptAndCombine({
accessControlConditions,
ciphertext,
dataToEncryptHash,
authSig: null,
chain: 'ethereum',
});
### Example Lit Action

Lit.Actions.setResponse({ response: resp });
})();`
The `decryptAndCombine` function uses the `accessControlConditions` to specify who and under what conditions the data can be decrypted. The `ciphertext` and `dataToEncryptHash` are the encrypted data and the hash of the data that was encrypted.

const res = await client.executeJs({
code,
sessionSigs: {} // your session
jsParams: {
accessControlConditions,
ciphertext,
dataToEncryptHash
We set the `authSig` to null as a way to tell the Lit Action runtime to use the `authSig` which was provided to the node when you call `executeJs`. It will use the AuthSig within the session signatures.
spacesailor24 marked this conversation as resolved.
Show resolved Hide resolved

Then our decrypted API key is used to query the blocknumber on Base.

```tsx
const _litActionCode = async () => {
try {
const apiKey = await Lit.Actions.decryptAndCombine({
accessControlConditions,
ciphertext,
dataToEncryptHash,
authSig: null,
chain: "ethereum",
});

const fullUrl = url + apiKey;

const resp = await fetch(fullUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "eth_blockNumber",
params: [],
}),
});

let data = await resp.json();

if (data.result) {
data.result = parseInt(data.result, 16);
}
});

console.log("decrypted content sent from lit action:", res);
Lit.Actions.setResponse({ response: JSON.stringify(data) });
} catch (e) {
Lit.Actions.setResponse({ response: e.message });
}
};

export const litActionCode = `(${_litActionCode.toString()})();`;
```

## Complete Example: Decrypting an API Key From Within an Action
The following example demonstrates how you can decrypt an API key within a Lit Action. Once decrypted, the API key can be used to perform a remote API call. Check out the complete code example [here](https://github.com/LIT-Protocol/developer-guides-code/tree/master/decrypt-api-key-in-action).
## Summary

This guide demonstrates how to use Lit Actions to decrypt data within a Lit Action.

If you'd like to learn more about Lit Actions, check out the [Lit Actions SDK](https://actions-docs.litprotocol.com/), or our [Advanced Topics](https://developer.litprotocol.com/category/advanced-topics-1) section on Lit Actions.