Indexer
About Indexer and how does it works
About Indexer works as a caching service for storing ciphertext against handle for faster retreival, Whenever a batch is processed by coprocessor before getting posted to Data storage layer it is sent to indexer for faster retreival on requirement later on. Indexer on it's end uses sled database to store ciphertext. While storing ciphertext against handle, It's don't just stores the ciphertext along with the ciphertext it stores couple of other parameters as well by which processor when later going to retreive these ciphertext can verify that these ciphertexts were indeed calculated within trees
Batch Tree Storage Workflow
The following diagram shows how the Processor submits batch trees to the Indexer after computation, and how the Indexer verifies and stores them:
Processing Steps:
- Processor sends batch tree with merkle root, TEE signature, leaf hashes, and batch requests
- Indexer verifies secp256k1 ECDSA signature over merkle_root using TEE public key
- For each request in batch: store handle → ciphertext mapping with inclusion proof
- Return success acknowledgement
Input: SetTreeAndLeavesRequest (merkle root, signature, leaves) Output: Verified ciphertext mappings stored in Sled database
The blob which is saved against the handle looks like this:
pub struct ComputedCiphertextResponse {
// will be saved against calculated resultant handle
pub ciphertext: Ciphertext,
pub cts: Vec<u8,>,
pub signature: Vec<u8,>,
pub merkle_root: [u8; 32],
pub leaf_hash: [u8; 32],
pub inclusion_proof: MerkleInclusionProof,
pub ciphertext_hash: [u8; 32],
pub is_new_ciphertext: bool,
pub request_params: RequestParams,
}Indexer as a service exposes couple of routes for processor to fetch and set ciphertext
These are:
/v1/set-ciphertext/v1/set-batch-tree/v1/get-ciphertext/v1/get-ciphertexts
Ciphertext Storage & Retrieval Workflow
The following diagram shows the simpler operations for storing and fetching individual ciphertexts:
Operation Details:
-
set-ciphertext - Store newly generated ciphertext
- Verifies TEE signature over ciphertext hash
- Stores single handle → ciphertext mapping
- Used when Processor generates new encrypted values
-
get-ciphertext - Fetch single ciphertext by handle
- Returns full ComputedCiphertextResponse with inclusion proof
- Enables verification that ciphertext was computed within TEE
-
get-ciphertexts - Batch fetch multiple ciphertexts
- Accepts vector of handles, returns vector of optional results
- Optimized for bulk retrieval during batch processing
Input (set): Handle + ciphertext + TEE signature Output (set): Storage confirmation
Input (get): Handle or Vec<Handle> Output (get): ComputedCiphertextResponse with merkle proofs
Route Details
/v1/set-ciphertext
- This route is useful in situation where processor need to make request store a single newly generated ciphertext. The endpoint expects
SetCiphertextRequeststruct which contains ciphertext which needs to be cached among indexer.
pub struct SetCiphertextRequest {
#[serde(with = "handle_serde")]
pub handle: Handle,
pub cts: Vec<u8,>, // ciphertext to be decrypted
pub ciphertext: Ciphertext,
pub signature: Vec<u8,>, // signature over ciphertext hash via TEE attestation key as a sign of acknowlegdement
}/v1/set-batch-tree
- This route is useful when processor construct a certain batch tree and when it completes processing a certain batch, Post that the batch tree is sent over to the indexer. The processor service constructs an struct of type
#[derive(Debug, Clone, Serialize, Deserialize,)]
pub struct SetTreeAndLeavesRequest {
#[serde(
serialize_with = "bytes32_serde::serialize_vec",
deserialize_with = "bytes32_serde::deserialize_vec"
)]
pub leaf_hashes: Vec<[u8; 32],>,
#[serde(with = "bytes32_serde")]
pub merkle_root: [u8; 32],
pub signature: Vec<u8,>,
pub batch_requests: Vec<PreComputedCiphertextRequest,>,
}The SetTreeAndLeavesRequest struct contains the whole batch tree along with the leaves and the signature over the batch tree root. The struct is then decoupled at the indexer set-batch-tree route and mapping of handle/pointer to Ciphertext blob is created
/v1/get-ciphertext
- This route is useful for fetching a certain ciphertext blob against a request handle. It returns
ComputedCiphertextResponsetype struct which contains necessary properties to verify that the ciphertext was indeed calculated within TEE. TheGetCiphertextsRequeststruct contains the handle of the ciphertexts which needs to be fetched. The struct is then decoupled at the indexer get-ciphertexts route and mapping of handle/pointer to Ciphertext blob is created
/v1/get-ciphertexts
- This route is useful for fetching a certain batch of ciphertext blobs against a requests handles. It returns vector of
(u128, Option<ComputedCiphertextResponse,>,)tuple against a vector of requested handles.
The request parameters to fetching vector of (u128, Option<ComputedCiphertextResponse,>,) looks like this
pub struct GetMultipleHandlesRequest {
#[serde(
serialize_with = "handle_serde::serialize_vec",
deserialize_with = "handle_serde::deserialize_vec"
)]
pub handles: Vec<Handle,>,
}