Decrypting Actions

After the ZKAP Validator verifies a private frame on-chain, it emits an AnonymousAction event containing the encrypted payload. Applications must decrypt this payload off-chain to recover the original instruction and execute the requested logic.

This file explains everything developers need to know about decrypting anonymous actions.


1. Where decryption happens

Decryption always happens off-chain, typically in:

  • backend services

  • DEX engines

  • agent orchestrators

  • bridge routers

  • indexer-like consumers

  • secure enclaves

  • specialized off-chain workers

Nothing in the encrypted payload should ever be decrypted inside a smart contract.


2. Anatomy of the AnonymousAction event

The validator emits:

AnonymousAction(commitment_root, encrypted_payload)

Where:

  • commitment_root is used to validate commitments

  • encrypted_payload is the ciphertext generated by the sender

Your application needs only the encrypted_payload to decrypt the action.


3. Requirements for decryption

To decrypt the payload, you must have:

  1. The application’s symmetric decryption key

  2. The ciphertext received from the event

  3. The same encryption scheme used by the sender (AES-GCM or ChaCha20)

  4. The correct IV/nonce (included in the ciphertext format)

The encryption key must be kept secure — it is the only piece of information that allows the payload to be read.


4. Using the SDK to decrypt payloads

The ZKAP SDK provides a simple helper function:

const payload = await decryptPayload(encrypted_payload, appKey);

This function:

  • validates ciphertext structure

  • extracts IV/nonce

  • performs authenticated decryption

  • returns the original JSON payload

If authentication fails, the payload will not decrypt.


5. Example: decrypting inside a backend listener

import { decryptPayload } from "@zkap/sdk";

contract.on("AnonymousAction", async (root, encrypted) => { try { const payload = await decryptPayload(encrypted, appKey); executeAction(payload); } catch (e) { console.error("Decryption failed:", e); } });

This pattern is the most common architecture for applications integrating ZKAP.


6. Example payload after decryption

After decrypting, the application sees the original instruction:

{ "action": "swap", "tokenIn": "USDC", "tokenOut": "ETH", "amount": "500", "minOut": "0.3", "expiry": 12345678 }

Only the application sees the content — nobody else can.


7. Encryption schemes supported

ZKAP supports:

  • AES-GCM

  • ChaCha20-Poly1305

Both provide:

  • confidentiality

  • authenticity (decryption fails on tampering)

  • integrity guarantees

Developers can choose the backend they prefer.


8. Handling invalid or corrupted ciphertext

The decryption function may throw errors when:

  • IV/nonce is missing

  • ciphertext was altered

  • wrong decryption key is used

  • payload is malformed

  • encryption backend mismatch

The SDK provides descriptive error messages.


9. Security model for decryption keys

Best practices:

  • Never embed keys in frontend code

  • Store keys in backend vaults (HashiCorp Vault, AWS KMS, GCP KMS)

  • Rotate keys periodically

  • Restrict who/what can decrypt payloads

  • Never expose keys in logs

  • Isolate decryption workers if possible

ZKAP relies entirely on off-chain decryption privacy, so key management is critical.


10. When to decrypt payloads

An application should decrypt payloads:

  • immediately after receiving the event

  • OR through a batch listener service

  • depending on business logic

For high-throughput applications (e.g., DEX/RFQ), parallel decryption workers may be used.

For agent runtimes, logic may require sequential processing.


11. Usage patterns across application types

Private DEX

Decrypt → read swap → execute routing logic.

Wallet backend

Decrypt → execute user operations or intents.

Agent system

Decrypt → trigger workflows, task execution, or multi-step logic.

RFQ engine

Decrypt → generate private quote → respond via ZKAP.

Bridge / Router

Decrypt → read cross-chain intent → dispatch to target chain.

Last updated