Inquiry Regarding Hybrid On-chain/Off-chain Architecture and KMS Key Rotations

Hello Zama Team,

I am currently developing a dapp using FHEVM. To optimize for scalability and significantly reduce gas overhead associated with on-chain storage, I am proposing a hybrid architecture that offloads a portion of the state to IPFS (via Pinata).

Proposed Architecture:

State Management: I plan to store larger encrypted datasets and project metadata on IPFS.

Execution: The smart contract will act as a stateless logic layer. Required parameters (Encrypted Variables + ZKPoK proofs) will be fetched from IPFS and passed into the contract functions for homomorphic processing.

Technical Inquiries:

KMS Key Rotations: Since the ciphertexts and ZK-proofs are generated on the frontend using the current KMS public key, how should the system handle periodic key rotations if the data is stored off-chain? Would a “Key-Switch” or re-encryption mechanism be required to ensure long-term data availability?

ZKPoK Validity: Given that the proofs are mathematically bound to the ciphertext, is there any scenario (outside of a network-wide key rotation) where a proof stored off-chain would become invalid for on-chain verification?

Dev Program Alignment: Does this “Stateless Logic” approach meet the technical requirements of the Zama Developer Program, provided that all financial computations remain on-chain using FHE?

I want to ensure this architecture is robust and doesn’t introduce “Data Availability” loopholes before I commit to the full implementation. I would appreciate your thoughts on this design.

Best regards,
Pratham Vajpayee

@poppyseeddev

Hey @Pratham_Vajpayee,

I am not sure how to answer your question, The main point of confusion seems to be that you’re thinking about the Zama Protocol a bit like a traditional blockchain execution environment where the full state lives on-chain. That’s not quite how FHEVM works. Most of the heavy lifting — the actual FHE computations and ciphertext storage — happens off-chain, while the chain itself only deals with handles (essentially references to ciphertexts) and access control.

So when a contract stores an euintX, what’s really stored on-chain is a handle (bytes32) that points to a ciphertext maintained by the coprocessor network. The Solidity library performs symbolic execution on handles, and the real FHE operations are executed asynchronously off-chain. This design is what allows the system to remain scalable while still keeping computations verifiable.

Because of that architecture, thinking about the protocol as a “stateless logic layer that pulls encrypted state from IPFS” may not map well to how the system is intended to operate. Ciphertexts, proofs, and access rights are tied into the Gateway, coprocessors, and ACL system, so moving encrypted state entirely outside that flow can introduce issues around verification, permissions, and data availability.

A few quick clarifications related to your questions:

  • KMS key rotation: You typically don’t need to design an application-level re-encryption flow. The protocol supports key rotation internally using key-switching, which allows ciphertexts created under older concrete keys to continue working with newer keys.

  • ZKPoK validity: The ZK proof mainly proves that the ciphertext is well-formed and that the sender knows the plaintext. It’s verified during the input-verification flow and tied to specific metadata (user, contract, chain). Treating those proofs as long-lived off-chain artifacts that can be replayed later isn’t really how the system expects them to be used.

  • “Stateless” architecture: Offloading non-confidential metadata off-chain is totally fine, but encrypted state itself is usually expected to live within the protocol’s ciphertext/handle system so that ACL permissions and verifiability remain intact.

If you want a deeper understanding of how the pieces fit together (handles, coprocessors, Gateway, KMS, etc.), I’d recommend prompting our Zama Protocol GPT, which is trained on the protocol docs and tech specs and can walk through the architecture in detail:

It should help clarify a lot of these mechanics before you finalize your architecture.

2 Likes

Thanks @poppyseeddev,

Thank you so much for the detailed clarification! This is incredibly helpful.

I’m currently building an HRMS + Payroll Dapp (essentially a confidential, Web3 version of Rippling) with advanced compliance and audit features. I actually pivoted my architecture twice trying to optimize for what I assumed would be massive gas costs.

To avoid on-chain congestion, I had moved the heavy audit computations (like the Gini Coefficient and payroll aggregates) off-chain, used bitmasking for reimbursement states, and even learned Noir to write custom ZK proofs and Merkle trees to verify that off-chain execution.

Your explanation that the FHEVM already maintains the ciphertexts via the coprocessor network and handles the ZK proofs during input-verification is a massive relief. It means I can scrap the custom Noir circuits and IPFS encrypted state, and rely entirely on the protocol’s native handles and ACL. I am pivoting my architecture back to a native FHEVM flow today.

By the way, since I am moving the logic back on-chain, I do have one quick follow-up regarding heavy computations: If my generateComplianceReport function needs to aggregate (e.g., sum up or find the max of) 50 to 100 encrypted employee salaries at once, is it safe/gas-efficient to pass that many externalEuint32 handles into a single smart contract function and loop through FHE.add()? Or is there a recommended pattern for batch-processing large arrays of ciphertexts within the Zama architecture without hitting gas limits?

Thanks again for saving me from massively over-engineering this!