Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Prisms & the Cloud Standard

A prism is an on-chain, namespaced vault dedicated to the index of your files (the reconstruction "routes"), not to the files themselves. The heavy data lives at your cloud providers; the prism only holds lightweight, encrypted, tamper-proof metadata.

Identity

A user's DataPrism identity is an Ethereum wallet address. Two entry points:

  • Existing wallet: connect MetaMask (or any compatible wallet) through the frontend (viem / wagmi).
  • PrismKey: for users without a wallet, DataPrism generates and manages one for them. The user never has to understand the blockchain.

That address serves as identity (prism ownership, request signatures), as the destination for purchased credits, and, crucially, as the source of the encryption key (see dataprism.key below).

Identifiers: protocolId & cloudId

Each prism has a bytes32 identifier, the protocolId: derived deterministically as keccak256(DataPrismCloud address, salt). On the application layer, a shortened cloudId (bytes16, the first 16 bytes of the protocolId) is used to reduce calldata cost.

Because the derivation is deterministic, the SDK can compute the cloudId offline (computeCloudId(address, salt)). This is what lets a prism created through the gasless API path know its ID immediately, without waiting for the relayer's confirmation.

Creating a prism

Creation goes through the SDK, which calls the on-chain creation function (DataPrismCloud.createPrism). Two paths, depending on whether the user holds gas:

            ┌──────── does the user hold ETH? ────────┐
            │ YES                                 NO   │
            ▼                                          ▼
   direct contract call                  call to dataprism-api
   (DataPrismCloud.createPrism)          with a signed request
   user pays the gas                     (EIP-712, gasless)
            │                                          │
            │                           dataprism-relayer executes
            │                           the transaction on-chain
            ▼                                          ▼
      prism created on-chain ◄───────────────────────┘

The SDK's execution layer makes both paths transparent, the calling code is identical. At creation, a prism is provisioned with a set of standardized data slots.

When a prism is created with an initial balance (fundAmount > 0), funding and creation happen in a single transaction: the SDK signs an EIP-2612 permit instead of a separate approve (createPrismWithPermit on the wallet path, createPrismFor with PermitParams on the API path). See Single-transaction funding.

Creation can also write an initial batch of data in the same atomic transaction, so a prism is created and populated in one signature and one nonce increment (equivalent to a createPrism immediately followed by batchWriteData, but atomic). The contract exposes:

  • createPrismWithData(fundAmount, salt, dataIds, payloads), on the wallet path.
  • createPrismWithDataAndPermit(fundAmount, salt, dataIds, payloads, deadline, v, r, s), which also bundles the EIP-2612 permit so a funded, populated prism is created with no separate approve.
  • createPrismWithDataFor(...) on the Forwarder for the gasless (API) path, and the createPrismWithDataAs callback that the Forwarder invokes.

Here fundAmount must cover the creation fee plus the per-entry data fees. The cloudId derivation is unchanged and stays deterministic, so it is known offline immediately. In the SDK this is the default behaviour of PrismManager.create(): it provisions the prism and writes the standard slots (key, encryption, metadata, providers) in one transaction, and any extra initialData entries are written in the same call. See the execution layer for the createPrismWithData method.

The Cloud Standard

The Cloud Standard is a naming convention for the reserved slots of a prism, the same idea as Ethereum's EIP/ERC standards, applied to cloud storage. Each slot is identified by a dataId = keccak256("dataprism.xxx") (a bytes32). The stored value is always JSON serialized to bytes; it is encrypted unless noted otherwise.

SlotdataIdEncrypted?Holds
dataprism.keykeccak256("dataprism.key")clearthe prism's public key
dataprism.encryptionkeccak256("dataprism.encryption")clearcurve + algorithm
dataprism.metadatakeccak256("dataprism.metadata")sealedname, description, member addresses
dataprism.providerskeccak256("dataprism.providers")sealedmanaged-storage service marker
file indexkeccak256(filename)sealedper-file reconstruction root

dataprism.key

{ "public": "", "private": "" }
  • public: the prism's public key. Readable by anyone (it is used to encrypt for the prism), so this slot is stored in clear.
  • private: the private key. Empty by default and never written on-chain.

The private key is not stored, it is derived on demand, client-side, from a wallet signature:

   connected wallet
        │  the user signs a deterministic message:
        │     • dataprism:key:${cloudId}              (default)
        │     • dataprism:key:${cloudId}:${password}  (extra security)

   signature (deterministic)

   = private key used by the SDK

   public key derived → written into dataprism.key.public

Why the cloudId? It is public and known from the prism's id, so the key is reproducible from the prism alone (no per-prism secret to store; works when listing prisms by cloudId). Why the optional password? Deriving from the cloudId alone means anyone who steals the wallet's private key could reproduce the signature and decrypt. Adding a password (dataprism:key:${cloudId}:${password}) makes it a second factor: decryption then also requires the password. The password is never stored, only mixed into the signed message.

The exact signed message is dataprism:key:${cloudId} (default) or dataprism:key:${cloudId}:${password} (with a password). The same message must be used at creation and on every read, or the derived key will not match.

Optional public mode: if the user accepts that anyone can read their data, they may choose to write private on-chain. This is an explicit, opt-in "public" mode.

dataprism.encryption

{ "curve": "secp256k1", "algorithm": "aes-256-gcm" }
  • curve: "secp256k1" | "x25519" | "ed25519"
  • algorithm: "aes-256-gcm" | "xchacha20"

These parameters define how the key (above) encrypts and decrypts everything else (metadata, providers, file indexes). Stored in clear so a reader knows how to decrypt the rest.

dataprism.metadata

{
  "name": "",
  "description": "",
  "addresses": { "0x...": "human-readable name" }
}
  • name: description, prism information.
  • addresses: the list of authorized owner / writer addresses, each mapped to a readable name.

This JSON is sealed (encrypted) with the parameters from dataprism.encryption.

dataprism.providers

A sealed JSON keyed by provider ID. New projects store only a public marker for DataPrism managed storage:

{
  "dataprism_managed": { "service": "dataprism" }
}

This marker contains no credentials. The signed-in user authorizes individual storage operations through the API, which returns short-lived URLs scoped to the project and object.

File index slots

In addition to the reserved slots above, each uploaded file creates a slot whose dataId is the hashed filename. Its value is the (sealed) JSON of the root reconstruction index: quorum, provider list, and a Merkle root (BlobRef) that points to the chunks/manifests stored at the providers. This root stays tiny (≈ a few hundred bytes) regardless of file size. See File Storage & Resilience.

Working with prisms in code

The SDK turns these concepts into a typed API, CloudStandard (encode/seal each slot), CloudReader (read + decrypt in one step), and PrismManager (single-transaction creation that also writes the standard slots, plus dedicated slot editors with a guard against overwriting reserved slots). See the SDK Cloud Standard page.

Copyright © 2026 DataPrism.