OpenMined / TenSEAL

A library for doing homomorphic encryption operations on tensors
Apache License 2.0
837 stars 158 forks source link

deepcopy doesn't work for public context #437

Open nvidianz opened 1 year ago

nvidianz commented 1 year ago

Description

Python copy.deepcopy() throws following exception when the context is public. It only occurs when encryption type is symmetric.

Traceback (most recent call last):
  File "/home/zhihongz/play/test/he_test.py", line 13, in <module>
    copied_vec = copy.deepcopy(new_enc_vec)
  File "/usr/lib/python3.10/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/usr/lib/python3.10/copy.py", line 271, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib/python3.10/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python3.10/copy.py", line 231, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python3.10/copy.py", line 153, in deepcopy
    y = copier(memo)
ValueError: the current context is public, it doesn't hold a Secret key

How to Reproduce

Run following test and it should show the exception,

import copy
import tenseal as ts
context = ts.context(ts.SCHEME_TYPE.CKKS, poly_modulus_degree=8192,
                     coeff_mod_bit_sizes=[60, 40, 40],
                     encryption_type=ts.ENCRYPTION_TYPE.SYMMETRIC)
context.global_scale = 2 ** 40
context.generate_relin_keys()
enc_vec = ts.ckks_vector(context, [123])
public_context = ts.context_from(context.serialize())
new_enc_vec = ts.ckks_vector_from(public_context, enc_vec.serialize())
copied_vec = copy.deepcopy(new_enc_vec)
print(type(copied_vec))

Expected Behavior

The deepcopy() should work for public context for both encryption types

System Information

Additional Context

The problem is at this line https://github.com/OpenMined/TenSEAL/blob/13486592953f82ca60502fd196016f815891e25a/tenseal/cpp/context/tensealcontext.cpp#L568

It tries to get secret_key even for public context. It should behave like save_proto_public_key(), not trying to save secret key when the context is public

youben11 commented 1 year ago

Indeed that's the root cause. Would be nice to have a PR to fix it :)

lunan0320 commented 1 year ago

I found the same problem as you when I serialize CKKS cipher in federated learning . I want to create process communication use torch.distributed.rpc, which uses deepcopy() to transfer cipher to server. I desire how to fix it.

image