1

A) I'm having trouble to understand the relationship between those setting:

parms.set_poly_modulus("1x^2048 + 1");
parms.set_coeff_modulus(coeff_modulus_128(2048));
parms.set_plain_modulus(1 << 8);

and this table from the SEAL manual.

enter image description here

I'm interested in particular in the number 54 and how was it calculated in respect to parms.set_poly_modulus("1x^2048 + 1") and parms.set_coeff_modulus(coeff_modulus_128(2048)).

B) I'm trying to find the right parameters for my use case. Let's say I have 10000 fractional numbers between -180 and +180 and I want to encode each of those numbers using the FractionalEncoder. The preformed operations are going to be: subtract, add, multiply, square and exponentiate. The result is going to be saved in a separate Ciphertext variable.

So in respect to my use case what are the optimal parameters for:

  1. n, q, t in

    parms.set_poly_modulus("1x^n + 1");
    parms.set_coeff_modulus(coeff_modulus_128(q));
    parms.set_plain_modulus(t);
    
  2. a and b in seal::FractionalEncoder encoder(context.plain_modulus(), context.poly_modulus(), a, b, 2). I'm using a = 512 and b = 128, which is way too high for my use case.

How can I calculate those parameters myself if my use case changes?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
TalG
  • 677
  • 1
  • 9
  • 26

1 Answers1

1

A) In your example you are using a polynomial modulus of dimension 2048 and the 128-bit security level default value for the coefficient modulus. To see what that value precisely is, take a look at SEAL/seal/util/globals.cpp. The coefficient modulus is a vector of SmallModulus objects, which are positive integers representing up to 60-bit factors of the total coefficient modulus. For example, for your parameters the coefficient modulus consists of just one single prime number factor 0x3fffffff000001, but you'll see that for larger parameters it can have many more factors.

The security level depends on both the degree of the polynomial modulus (larger is higher security) and the bit-length of the total coefficient modulus (smaller is high security). Thus, for a fixed polynomial modulus there should be a largest acceptable coefficient modulus providing a fixed level of security. Since it is not at all easy to know what this upper bound on the coefficient modulus is, SEAL provides it conveniently as the default value through coeff_modulus_128 (and coeff_modulus_192 and coeff_modulus_256 for higher security levels). In some cases you may want to use a smaller coefficient modulus than the default, but you should never use a larger one unless you really know what you are doing (and probably not even then). The bit-length of 54 bits is obtained using Martin Albrecht's LWE estimator: https://bitbucket.org/malb/lwe-estimator.

B) A typical workflow in determining parameters in this kind of situation would be to first figure out a large enough plain_modulus so that you get correctness for your computation. If you run out of noise budget, just tune up your coeff_modulus until it works.

Once you have found a large enough plain_modulus, try to optimize coeff_modulus by setting it to a smallest value leaving you with non-zero noise budget. For simplicity, you could just try the different default values obtained through coeff_modulus_128. If you really care a lot about performance you may want to hand-pick your coeff_modulus prime numbers to really find the smallest value that works.

Next, choose your poly_modulus to be large enough so that your total coefficient modulus is at most equal to the default value for that poly_modulus degree.

Finally you may want to hand-tune the decomposition_bit_count used in relinearization. By default you should use the value 60 which results in better computational performance but more noise growth. In some cases you may want to drop this to e.g. 30, if you happen to be in a situation where some extra noise budget saved would allow you to switch to smaller encryption parameters. In most cases this level of fine-tuning should not be necessary.

What exactly the resulting optimal parameters will be depends totally on your computation, so without very specific details it's impossible to give a direct answer here.

Parametrization of the FractionalEncoder is a different matter. I would recommend experimenting with different values to get an idea of how these choices affect accuracy. What is wrong with the a=512, b=128 choice?

Kim Laine
  • 856
  • 5
  • 10
  • If I understood it correctly, then having a=512 for a number that has a maximum of 180 in the integer part is way to big. b=128 offers a lot of precision that is rarely needed. I'll do some parameter testing with smaller values. – TalG Sep 04 '18 at 21:28
  • could you please explain this **"Next, choose your poly_modulus to be large enough so that your total coefficient modulus is at most equal to the default value for that poly_modulus degree."** – TalG Sep 04 '18 at 21:31
  • Say you notice you need at least coeff_modulus_128(8192) for noise budget and correctness, then take poly_modulus “1x^8192 + 1”. If you go with a more performance-tuned approach and hand-pick your coeff_modulus primes, then you may notice that e.g. 160 bits of coefficient modulus suffices. Looking at the bounds in globals.cpp you notice that the safe coeff_modulus upper bound for 128 bits of security for poly_modulus degree 4096 is around 110 bits and for degree 8192 it is twice that. Your goal of 160 bits would then require going up to degree 8192 to remain secure. – Kim Laine Sep 04 '18 at 22:20
  • Thanks for mentioning `globals.cpp`! I saw that the bit counts correspond with the published table. I also saw that for higher `poly_modulus` degree e.g. 8192 the default bit count using `coeff_modulus_128(8192)` consists of several primes with a total of 218 bits. If I want to hand-pick my `coeff_modulus` primes for 8192, can I use several primes that have a bit count in a range of 110(120) - 218 bits or should I consider a different bit range? I assume 109 bits to be the upper bound for `poly_modulus` degree 4096 and 218 bits for `poly_modulus` degree 8192. – TalG Sep 08 '18 at 07:55
  • Only the upper bound matters. Smaller coeff_modulus is always more secure. Yes, you can hand-pick the primes you want. – Kim Laine Sep 08 '18 at 16:47
  • OK, but I can't use a total bit count of 100 bits for a 8192 degree if I use the table as reference for my settings, because then I'm actually in the 4096 degree range. So if I use a 8192 degree then I shouldn't have a total bit count of primes in a range that is suitable for 8192 and not for 4096, right? Or using one prime with 54 bits for a 8192 degree is also ok? If yes, then why would anyone use a higher total bit count of primes if lower is better? – TalG Sep 08 '18 at 17:04
  • From larger coeff_modulus you get more noise budget; this is the reason for using the upper bound as SEAL default. However, sometimes this is too much noise budget so for performance reasons you may want to use a smaller one. It can even make sense to go down to the 4096 secure region with 8192 size poly_modulus if you need more than 4096 slots for batching, but if that is not the case then you should switch to smaller poly_modulus. – Kim Laine Sep 08 '18 at 17:32
  • I got a little confused with by the last comment. I thought that the `parms.set_plain_modulus()` parameter is responsible for the noise budget. If not then what is it for? – TalG Sep 08 '18 at 17:38
  • After doing some more reading, I think I got it right. The `parms.set_plain_modulus(t)` sets the representation of each number element to be in range (0, t-1). Does that mean if I want to encode the number 37, then 3 and 7 will be represented as a separate numbers in range (0, t-1) or the whole number is encoded in range (0, t-1)? If I got the usage/meaning of `parms.set_plain_modulus()` wrong then could you please explain it to me? – TalG Sep 08 '18 at 19:57