Skip to main content

The evaluation key

You met the evaluation key on Concepts: generated on your machine, uploaded to the server once, it lets the worker compute on your ciphertexts without ever being able to read them. What Concepts left out is that its size is not fixed: it is a direct consequence of the pipeline you built and the parameters you chose on the previous pages. This page is about what's inside the key, which operators need which part, and what makes it large.

Where it comes from

The key pair is generated by query_client.generate_key(load_if_exists=False), the call you saw on Deploy the Pipeline in the Key generation stage. The secret key stays on your machine. The evaluation key is uploaded to the platform as one object and held by the worker for every query after that. Generation takes longer than a query does, but it happens once per deployment.
What goes into that object is decided at compile time: the compiler walks your pipeline, collects what each operator will need, and the key is generated to match. A pipeline that needs less gets a smaller key.

What's inside

The evaluation key has two components:
Square key: one, small.

After two ciphertexts multiply, the result has to be folded back into normal ciphertext form: the step is called relinearization, and the square key is what performs it. It is a single object, the same size whatever your pipeline does, and it's included whenever ciphertexts multiply anywhere in the pipeline.

Rotation key: one entry per offset.

Lets the worker rotate ciphertext slots. It is not one universal key: it is built from entries (each a small key of its own) - one for every distinct offset. This is the component that grows.

Only what your pipeline needs is included.
  • No ciphertext multiplies no square key.

  • No cross-slot work no rotation key.

  • Bootstrap is not a third component: when present, it adds its own rotation offsets, needs the square key, and adds dense↔sparse switching keys, inside the same key material.

One entry per offset

To rotate by a given offset, the worker needs the entry generated for that exact offset: rotating by 2 uses the offset-2 entry, and rotating by 512 needs a different one, generated for offset 512. Reusing an offset costs nothing: its entry is already in the key. Every new offset adds one, and each entry is roughly the size of a ciphertext:
what makes the key growROTATION KEY
rotate by 2, many times            →  1 entry
rotate by 1, 2, 3, … 1023, once    →  1,023 entries
So what decides the rotation key's size is not how often your pipeline rotates, but how many different offsets it uses. Where those offsets come from is the next two sections.

Which operators need what

Each operator in your compiled pipeline declares what it needs (the square key if it multiplies ciphertexts, rotation entries if it works across slots, nothing if it does neither), and the evaluation key is generated as the sum of those declarations. That's the mechanism behind "a pipeline that needs less gets a smaller key."
You don't need to memorize the mapping. Every operator's reference page states its requirement in the Keys field. A few examples, just to show the pattern:
OperatorKeys field
HomMulSquare key: it multiplies two ciphertexts
HomSumSlotsRotation key: it works across slots
HomMatMulBoth when multiplying over the n axis: square and rotation keys
HomRingSwitchRing-switch key, square key, and the inner bootstrap's rotation keys
HomAdd, HomReshapeNone: no key needed
Examples only; the Keys field on each operator's reference page is the source of truth.
The operators that need the rotation key carry one more parameter: stage_sizes, their stage plan. It decides which offsets the operator rotates by, and therefore how many entries it asks the key to include. How stage plans work is covered on Slots, rotations & stages.

What makes it big

The size of the evaluation key is a product of two factors: how many entries it holds, times how big each entry is. The two factors have different owners.
The number of entries: set by your operators.

Everything from the previous section: which key components exist at all, and how many rotation entries there are, decided by the operators you placed and, for the ones that rotate, the stage_sizes you gave them.

The size of each entry: set by your context parameters.

Every entry is a cryptographic object built over the ring you configured, so it scales with the ring dimension n, with the total modulus from full_q_list_precision, and with the key-switching setting (decomposition_type, plus num_special_primes for hybrid or bv_gadget_bits for BV). Those are set once, at context creation, on Choosing parameters.

The factors multiply: a wide stage plan on a large ring with a long chain pays for every extra entry at the larger entry size. Of the two, the entry count is the one that moves furthest, and the one you'll tune most often. The same operation, two stage plans:
Sum over 1024 slotsRotation-key entries
stage_sizes = (2,) × 10 (default)~10
stage_sizes = (1024,) (collapsed)~1,023: roughly 100× the rotation key
The trade this buys (fewer rounds, faster query) is on Slots, rotations & stages.

Where the size costs you

01. Generation, once.

A bigger key takes longer for generate_key() to produce on your machine.

02. Upload, once.

The whole key travels to the platform in one upload. Its size is your bandwidth cost, paid at key generation.

03. GPU memory, the whole run.

The worker holds the full key in GPU memory for as long as it serves queries. Expect a resident footprint comparable to the uploaded size, plus working headroom: memory a large key occupies is memory your queries can't use.

In practice, a small pipeline with few or no rotations stays in the tens of megabytes, while a bootstrapping pipeline with a long chain can reach gigabytes. When the key is the bottleneck (slow generation, slow upload, a worker short on memory), the fix is on the pages above: narrower stage plans, a shorter chain, a smaller n.

Next

The offset count is the driver you'll tune most often; Slots, rotations & stages is where that happens. The other two drivers are set with the rest of your encryption parameters on Choosing parameters.