microsoft / SEAL

Microsoft SEAL is an easy-to-use and powerful homomorphic encryption library.
https://www.microsoft.com/en-us/research/group/cryptography-research/
MIT License
3.61k stars 709 forks source link

Question about the result of two-time encryption #566

Open Ten000hours opened 2 years ago

Ten000hours commented 2 years ago

Hi,

I have a question about the result after the encryption for ciphertext two times using CKKS scheme. The whole process of what I did is: encrypt an numpy array --> ciphertext multi_plain with plaintext(numpy array) --> decrypt the result ciphertext --> re-encrypt the result --> ciphertext multi_plain plaintext --> decrypt for getting result. The reason for two times encryption is to refresh the noise budget. Everything works well until I get the result after the second multi_plain. Here is the question:

if I choose a relatively small value, like 400, for the plaintext part(the variable kenel in the following code), it will produce the correct result after two-time multiplication. But when I choose a value like 4000 for plaintext, it outputs the wrong result. Why it happens?

result for choosing 4000 for b ( wrong for 001 : should equal to 4000 4000 1) image

result for choosing 400 for b( correct for 001 : 400 400 1 ) image

The main code is following ( sorry for using python version of SEAL for demo, I think it works just as SEAL since it using backbone of SEAL):

input_message = np.arange(0, 64).reshape(8, 8)
slot_count, scale, encryptor, evaluator, decryptor, galois_keys, ckks_encoder,relin_key,context = Setup()
a =  encryptor.encrypt(ckks_encoder.encode(input_message.flatten(), scale)
kenel = np.full((3,3),483)
b=ckks_encoder.encode(kenel.flatten(), scale)    
---------first multi-------------
evaluator.multiply_plain_inplace(a, b)

-------re-encrypt--------------
input = ckks_encoder.decode(decryptor.decrypt(a))
slot_count, scale, encryptor, evaluator, decryptor, galois_keys, ckks_encoder, relin_key, context = Setup()
plain_matrix1 = ckks_encoder.encode(input, scale)
a = encryptor.encrypt(plain_matrix1)    
b=ckks_encoder.encode(kenel.flatten(), scale)
--------------second multi-----------------
evaluator.multiply_plain_inplace(a, b)
--------decrypt--------    
check_res = ckks_encoder.decode(decryptor.decrypt(a))

The CKKS setup code:

parms = EncryptionParameters(scheme_type.ckks)
poly_modulus_degree = 4096
parms.set_poly_modulus_degree(poly_modulus_degree)
parms.set_coeff_modulus(CoeffModulus.Create(
    poly_modulus_degree, [36,37,36])) #36,36,37
scale = 2.0**30
context = SEALContext(parms)
print_parameters(context)
WeiDaiWD commented 2 years ago

The encrypted values have an upper-bound defined by coeff_modulus. One of your results grows too close to 2.0**(36+37-30), for example, 63 4000 4000 has 30 bits. We can confirm whether this is the cause by setting all input messages to 1. Would you please give it a try?

Ten000hours commented 2 years ago

The encrypted values have an upper-bound defined by coeff_modulus. One of your results grows too close to 2.0**(36+37-30), for example, 63 4000 4000 has 30 bits. We can confirm whether this is the cause by setting all input messages to 1. Would you please give it a try?

Thanks for your reply. I have given a go for setting all input message to 1, which means 1 4000 4000 for all values in the component-wise matrix multiplication, but still produces wrong result. Also, how close do you think it would be "dangerous" to produce an incorrect result? What is the range for "too close"?

WeiDaiWD commented 2 years ago

Would you please simply and share your code so that I can reproduce the error and debug it?

Ten000hours commented 2 years ago

Sorry for late reply. Please check the link below for my code. https://codecollab.io/@proj/GrayCartGray It imported the Python lib of SEAL, please check the link for installation: https://github.com/Huelse/SEAL-Python

WeiDaiWD commented 2 years ago

When encoding integers into a plaintext-only object, you can choose scale = 1.0; this applies to b.