A ZKAP Frame is the core object that replaces traditional blockchain transactions.
Instead of sending a public, metadata-rich transaction, developers use the SDK to construct an encrypted, zero-knowledge–validated frame that can be submitted to the ZKAP Validator contract.
This file explains how to build a ZKAP Frame step-by-step:
identity → payload → encryption → proof → frame assembly.
1. What is a ZKAP Frame?
A ZKAP Frame is a structured object containing:
a commitment binding the payload
encrypted payload (ciphertext)
a nullifier (to prevent replay attacks)
The final frame looks like this conceptually:
Copy {
zk_proof: "0x...",
commitment_root: "0x...",
payload_ciphertext: "0x...",
nullifier: "0x...",
session_hash: "0x...",
expiry_block: 12345678
} Every field is essential for validity and anonymity.
2. Prerequisites before building a frame
Before building a frame, you must have:
An ephemeral anonymous identity
A symmetric encryption key
Access to the ZK proof system
The expiry block for the request
These are typically created using the SDK.
3. Step 1 — Generate an Anonymous Identity
Identity is ephemeral and unlinkable.
Example (SDK function):
const id = generateIdentity();
This identity is used only inside the proof.
4. Step 2 — Create the Payload
A payload is a plain object representing the action.
Example:
This data will be encrypted before being added to the frame.
5. Step 3 — Encrypt the Payload
Encryption ensures no one can read the payload except the destination application.
Example:
const ciphertext = await encryptPayload(payload, sessionKey);
The ciphertext hides all details, including:
6. Step 4 — Generate the Zero-Knowledge Proof
The proof validates:
commitment root consistency
Example (conceptual):
The blockchain will verify this proof using the ZKAP Validator.
7. Step 5 — Build the Commitment Root
The commitment root binds the encrypted payload and expiry together.
commitment_root = Hash(payload_hash || expiry_block)
This guarantees that the payload cannot be tampered with after proof generation.
8. Step 6 — Derive the Nullifier
The nullifier prevents replay attacks.
const nullifier = deriveNullifier(id, nonce);
A nullifier:
reveals nothing about identity
It’s the only persistent state stored by the validator.
9. Step 7 — Create the Session Hash
The session hash provides optional context for ephemeral flows.
const sessionHash = createSessionHash(id, payloadHash);
This makes correlation between actions impossible.
10. Step 8 — Assemble the ZKAP Frame
Now combine all components:
This frame is what gets submitted to the blockchain.
11. Step 9 — Submit the Frame
Once assembled, the frame can be submitted to the ZKAP Validator:
await submitFrame(frame);
If the proof verifies and nullifier is fresh,
a AnonymousAction event is emitted.
12. Example Code (Putting It All Together)
Below is a simplified conceptual example:
The SDK abstracts many low-level details, making integration simple.