Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@
"sdk/resources/network-status"
]
},
{
"group": "Guides",
"pages": [
"guides/lit-action-sign-as-action"
]
},
{
"group": "FAQ",
"pages": [
Expand Down
71 changes: 71 additions & 0 deletions docs/guides/lit-action-sign-as-action.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: 'Derive Lit Action Public Keys'
description: 'How to deterministically derive and verify a Lit Action identity without executing it externally.'
---

# Derive a Lit Action Public Key Locally

## Question

I want to call `Lit.Actions.signAsAction`. I know the action identity is derived from the Action's IPFS CID, but I cannot find a way to obtain the public key outside of the Action runtime. `Lit.Actions.getActionPublicKey` works within the Action, while `executeJs` only exposes `signatures.<name>.publicKey` after a signing operation. Is there a way to deterministically derive the Action's public key locally without running the Action?
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

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

The question describes obtaining the public key 'outside of the Action runtime' and 'locally without running the Action', but the answer demonstrates deriving the key from within the Action context. This creates confusion about whether the solution actually addresses the stated problem of getting the key without executing the Action.

Copilot uses AI. Check for mistakes.

## Answer

Yes. Inside the Lit Action you can deterministically derive the Action identity (and therefore its public key) from the same inputs the nodes use: the Action's IPFS CID and the signing scheme. The snippet below shows the complete flow:

1. Produce the 32-byte message hash the Lit nodes expect.
2. Call `Lit.Actions.signAsAction` to sign that message with the Action identity.
3. Derive the Action public key via `Lit.Actions.getActionPublicKey`, passing the Action CID and signing scheme.
4. Optionally verify the signature with `Lit.Actions.verifyActionSignature`.

```js
const { sigName, toSign } = jsParams; // 'publicKey' not required; derive it from the Action IPFS CID
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

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

The comment states 'derive it from the Action IPFS CID', but the code doesn't demonstrate deriving anything at this line. The derivation happens later at line 43. This comment could mislead readers about where the derivation actually occurs.

Suggested change
const { sigName, toSign } = jsParams; // 'publicKey' not required; derive it from the Action IPFS CID
const { sigName, toSign } = jsParams; // 'publicKey' not required in jsParams; it will be derived later from the Action IPFS CID

Copilot uses AI. Check for mistakes.
const { keccak256, arrayify } = ethers.utils;

(async () => {
// 1) Produce a 32-byte hash of the input (Lit Actions expect a 32-byte message for ECDSA schemes)
const msgBytes = new TextEncoder().encode(toSign);
const msgHashHex = keccak256(msgBytes); // 0x-prefixed hex string
const msgHashBytes = arrayify(msgHashHex); // Uint8Array

// 2) Sign as the current Lit Action (deterministic Action identity, not a PKP)
// Supported schemes include 'EcdsaK256Sha256' (secp256k1) among others.
const signingScheme = 'EcdsaK256Sha256';
const signature = await Lit.Actions.signAsAction({
toSign: msgHashBytes,
sigName,
signingScheme,
});

// 3) Derive this Action's public key deterministically from its IPFS CID + scheme
// This does not require a PKP and is always the same for a given (CID, scheme).
const actionIpfsCid = Lit.Auth.actionIpfsIdStack[0];
const actionPublicKey = await Lit.Actions.getActionPublicKey({
signingScheme,
actionIpfsCid,
});

// 4) (Optional) Verify that the signature was produced by this Action identity
const verified = await Lit.Actions.verifyActionSignature({
signingScheme,
actionIpfsCid,
toSign: msgHashBytes,
signOutput: signature,
});

// 5) Return a structured response for clients to consume
Lit.Actions.setResponse({
response: JSON.stringify({
sigName,
signingScheme,
message: toSign,
messageHash: msgHashHex,
signature, // string; format depends on scheme
actionPublicKey, // string; hex or JSON depending on scheme
verified, // boolean
}),
});
})();
```

This approach keeps the derivation entirely within the Lit Action context. Because the public key depends only on the Action CID and signing scheme, you can rely on `Lit.Actions.getActionPublicKey` for a deterministic identity without needing to execute the Action externally first.
Loading