Encifher

Ciphertext Verification

How do we make sure when fetching ciphertext from indexer that the ciphertext was indeed calculated within TEE

Indexer acts as a caching service for processor client to fetch and update ciphertext along with certain parameters which enables necessary integrity checks that the ciphertext was previously computed within TEE.

Whenever processor client requests for a certain ciphertext against a handle it receives ComputedCiphertextResponse struct which follows

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,
}

The ComputedCiphertextResponse struct contains the ciphertext along with certain parameters which enables necessary integrity checks that the ciphertext was previously computed within TEE.

  • ciphertext: The ciphertext itself
  • cts: The cts of the ciphertext (actual payload which is encrypted)
  • signature: The signature over the merkle root of batch tree.
  • merkle_root: The merkle root of the batch tree (tree which contains all the ciphertext which were computed within TEE)
  • leaf_hash: The hash of the leaf of the batch tree the leaf hash (inherently contains ciphertext hash)
  • inclusion_proof: The inclusion proof of the leaf in the batch tree
  • ciphertext_hash: The hash of the ciphertext (hash of the ciphertext which was computed within TEE)
  • is_new_ciphertext: Whether the ciphertext is new or not
  • request_params: The request parameters (parameters of the request which was used to compute the ciphertext)

When the processor client receives ciphertext. It perform the below mentioned checks to make sure it's working on a ciphertext which is previously computed within coprocessor.

  1. Verify the signature aganst merkle_root against a whitelisted TEE public key. Which gives a guarrantee that we're working with a valid merkle tree.
  2. Compute the leaf_hash using ciphertext, cts and request_params.
  3. Verifies the inclusion proof of leaf_hash against the merkle_root to make sure the leaf_hash is a part of merkle tree which is signed.
  4. If both of the above checks passes the processor moves forward and starts using the ciphertext for further computation.