openfheorg / openfhe-python

Official Python wrapper for OpenFHE. Current release is v0.8.8 (released on June 25, 2024).
https://openfheorg.github.io/openfhe-python/html/index.html
BSD 2-Clause "Simplified" License
60 stars 18 forks source link

DeserializeEvalMultKey overwrites keymap content #144

Closed erik-3milabs closed 3 days ago

erik-3milabs commented 1 month ago

In my application, I'm receiving CryptoContext objects from multiple origins, along with a EvalMultKey. When "ingesting" (through DeserializeEvalMultKey) the EvalMultKeys, it seems earlier ingested keys are overridden.

A minimal example demonstrating the issue:

from openfhe import *

# NOTE:
# If running locally, you may want to replace the "hardcoded" datafolder with
# the datafolder location below which gets the current working directory
datafolder = 'demoData'

# Save-Load locations for keys
multKeyLocation1 = datafolder + '/key_mult1.txt'
multKeyLocation2 = datafolder + '/key_mult2.txt'

# Generate CC params
# Settings are arbitrarily chosen
parameters = CCParamsCKKSRNS()
parameters.SetMultiplicativeDepth(5)
parameters.SetScalingModSize(40)
parameters.SetBatchSize(32)

# Generate CC
cc = GenCryptoContext(parameters)
cc.Enable(PKE)
cc.Enable(KEYSWITCH)
cc.Enable(LEVELEDSHE)
# ... with keypair
kp1 = cc.KeyGen()
cc.EvalMultKeyGen(kp1.secretKey)   

# Generate an second, identical, context
cc2 = GenCryptoContext(parameters)
cc2.Enable(PKE)
cc2.Enable(KEYSWITCH)
cc2.Enable(LEVELEDSHE)
# ... with different keypair
kp2 = cc2.KeyGen()
cc2.EvalMultKeyGen(kp2.secretKey)    

# Encrypt some data, ONLY UNDER KP1
vec1 = [1.0, 2.0, 3.0, 4.0]
vec2 = [12.5, 13.5, 14.5, 15.5]
p1 = cc.MakeCKKSPackedPlaintext(vec1)
p2 = cc.MakeCKKSPackedPlaintext(vec2)
c1 = cc.Encrypt(kp1.publicKey, p1)
c2 = cc.Encrypt(kp1.publicKey, p2)

# Serialize the relinearlization keys of both contexts
assert CryptoContext.SerializeEvalMultKey(multKeyLocation1, BINARY, kp1.secretKey.GetKeyTag())
assert CryptoContext.SerializeEvalMultKey(multKeyLocation2, BINARY, kp2.secretKey.GetKeyTag())

# Release context, i.e. drop the relinearization keys from memory
cc.ClearEvalMultKeys()
ReleaseAllContexts()

# Deserialize the first relinearization keys
assert CryptoContext.DeserializeEvalMultKey(multKeyLocation1, BINARY)
cc.EvalMult(c1, c2) # this works, no problem

# Now, we deserialize the second key.
assert CryptoContext.DeserializeEvalMultKey(multKeyLocation2, BINARY)
cc.EvalMult(c1, c2) # raises RuntimeError

The error raised:

RuntimeError: cryptocontext.cpp:l.183:GetEvalMultKeyVector(): Call EvalMultKeyGen() to have EvalMultKey available for ID [...]

Note here that c1 and c2 were encrypted under cc. Before deserializing the EvalMultKey for cc2, there is no problem executing cc.EvalMult on these ciphertexts, but afterwards the key seems to be gone.

To further support the claim that the keys are OVERRIDDEN, I present the following code.

EXPORT_ALL_KEYS = ""
multKeyLocation3 = datafolder + '/key_mult3.txt'
assert CryptoContext.SerializeEvalMultKey(multKeyLocation3, BINARY, EXPORT_ALL_KEYS)

import hashlib
def get_digest(file):
    with open(file, 'rb') as fp:
        return hashlib.sha1(fp.read()).hexdigest()

print(f"keydigest CC/KP1  : {get_digest(multKeyLocation1)}")
print(f"keydigest CC2/KP2 : {get_digest(multKeyLocation2)}")
print(f"keydigest ALL_KEYS: {get_digest(multKeyLocation3)}")

When replace the statement that raised an exception with this code and execute, I see that the second and third hash that are printed are identical:

keydigest CC/KP1  : 6cdeda8a12afc1dfecb0f7724c803f6ea392a03a
keydigest CC2/KP2 : 2a18578c6db5c5056550df3e6587dc558771d89f
keydigest ALL_KEYS: 2a18578c6db5c5056550df3e6587dc558771d89f

This suggests that the second key is the only one stored.

All was executed using the latest main branches of openfhe-development and openfhe-python.

Am I doing something wrong? Any clue how I should resolve this?

erik-3milabs commented 1 month ago

@yspolyakov @dsuponitskiy :)

yspolyakov commented 3 days ago

@dsuponitskiy it looks like the issue comes from OpenFHE. I've created an issue for it: https://github.com/openfheorg/openfhe-development/issues/826