1

Let's say I calulated addition or multiplication of 2 Ciphertexts and seved the result in a third one. If I want to perform additional mathematical operations on my result Ciphertext (destination Chipertext), is it advisable to use evaluator.relinearize() on it before doing so? Because if I understood it correctly, some operations on Ciphertext cause the result Ciphertext size to be larger than 2. If yes, then would this be a good approach for relinearizing one Ciphertext?

  • EvaluationKeys ev_keys;
  • int size = result.size();
  • keygen.generate_evaluation_keys(size - 2, ev_keys); // We need size - 2 ev_keys for performing this relinearization.
  • evaluator.relinearize(result, ev_keys);
TalG
  • 677
  • 1
  • 9
  • 26

1 Answers1

2

Only Evaluator::multiply will increase the size of your ciphertext. Every ciphertext has size at least 2 (fresh encryptions have size 2) and multiplication of size a and b ciphertexts results in a ciphertext of size a+b-1. Thus, multiplying two ciphertext of size 2 you'll end up with a ciphertext of size 3. In almost all cases you'll want to relinearize at this point to bring the size back down to 2, as further operations on size 3 ciphertext can be significantly more computationally costly.

There are some exceptions to this rule: say you want to compute the sum of many products. In this case you might want to relinearize only the final sum and not the individual summands, since computing sums of size 3 ciphertexts is still very fast.

To make relinearization possible, the party who generates keys needs to also generate evaluation keys as follows:

EvaluationKeys ev_keys;
keygen.generate_evaluation_keys(60, ev_keys);

Later the evaluating party can use these as:

evaluator.relinearize(result, ev_keys);

Here I used 60 as the decomposition_bit_count in generate_evaluation_keys, which is the fastest and most often best choice. You should probably never use a int count parameter different from 1 (default) in generate_evaluation_keys. This is meant for use-cases where you let your ciphertexts grow in size beyond 3 and need to bring them down from e.g. size 4 or 5 down to 2.

Kim Laine
  • 856
  • 5
  • 10
  • So using `keygen.generate_evaluation_keys(60, ev_keys);` with `evaluator.relinearize(result, ev_keys);` is still a good choice even if I compute a multiplication of 3 or 4 Chiphertexts (each of size 2) into a new Chiphertext result of size 4 or 5? – TalG Sep 03 '18 at 20:13
  • No; in those cases you need a larger count. But typically you should never let your ciphertexts grow past size 3, which you can achieve by relinearizing after every multiplication (except multiply_plain) as in your example. – Kim Laine Sep 04 '18 at 22:08
  • `generate_evaluation_keys(60, ev_keys)` consumes a lot the noise budget when using `evaluator.relinearize(result, ev_keys)` compared to `generate_evaluation_keys(16, ev_keys)`, which didn't consume anything from the noise budget and did the same job. Are there other limitations with using 16 instead of 60 except the computational speed? – TalG Sep 17 '18 at 09:41
  • It's just about performance and the size of the evaluation keys. Same applies for Galois keys, but since the number of Galois keys of typically much larger it's more important to keep the DBC as big as possible. – Kim Laine Sep 17 '18 at 22:53
  • Since I don't operate on matrices I don't use any Galois keys. So If I performance is not an issue and want to keep as much of the noise budget as possible, I need to keep the DBC in `keygen.generate_evaluation_keys(dbc, ev_keys)` as small as possible? – TalG Sep 18 '18 at 06:34
  • 1
    Correct, but beyond a certain point it doesn't change anything since the noise in a fresh ciphertext is already bigger than the noise increase from relinearization. Something like 15 or 20 is really small DBC and it's hard to imagine a reason to go smaller than that. – Kim Laine Sep 18 '18 at 07:21