Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Value Error: encrypted1 and encrypted2 parameter mismatch #240

Open
eduardo-sarmento opened this issue Jun 19, 2024 · 2 comments
Open

Value Error: encrypted1 and encrypted2 parameter mismatch #240

eduardo-sarmento opened this issue Jun 19, 2024 · 2 comments
Labels

Comments

@eduardo-sarmento
Copy link

Description
Hello. I have been trying to implement the Central Kernal Aligment(CKA) similarity with Fully Homomorphic Encryption using Pyfhel. However, I have been running into the Value Error: encrypted1 and encrypted2 parameter mismatch in the last line of the implementation (result = top*bottom). I read in the documentation that using the rescale_to_next and align_mod_n_scale methods can resolve this problem, but when I use them I get a "cannot align scales 30 and 120: available rescaling [30 60]" warning. Most strangely is that sometimes it works when I use those methods, and it keeps working for a time, but if I try the same code latter it suddenly stops working.

Code To Reproduce Error

def cka_unecrypted(X, Y, XTX, YTY):
    # Implements linear CKA as in Kornblith et al. (2019)
    X = X.copy()
    Y = Y.copy()
    YTX = Y.T.dot(X)
    return (YTX**2).sum() * XTX * YTY


def cka_encrypted(X, Y, XTX, YTY, HE):
    X = X.copy()
    Y = Y.copy()
    if len(X) == len(Y) == 1:
        YTX = X[0] @ Y[0]
    else:
        YTX = [~(X[i] * Y[i]) for i in range(len(X[i]))]
        for i in range(1, len(YTX)):
            YTX[0] += YTX[i]
        YTX = HE.cumul_add(YTX[0])
    bottom = XTX * YTY

    HE.relinearize(bottom)

    square = YTX * YTX
    HE.relinearize(square)

    top = HE.cumul_add(square, False, 1)
    HE.relinearize(top)
    # Tried reescales
    # HE.rescale_to_next(bottom)
    # HE.rescale_to_next(top)
    # top, bottom = HE.align_mod_n_scale(bottom,top)

    # problem line
    result = bottom * top
    HE.relinearize(result)
    return result


def cka(X, Y, XTX, YTY, HE=None, crypt=False):
    if crypt:
        res = cka_encrypted(X, Y, XTX, YTY, HE)
    else:
        res = cka_unecrypted(X, Y, XTX, YTY)
    return res


rng = np.random.default_rng(42)
CASE_SELECTOR = 1  # 1 or 2

case_params = {
    1: {"l": 256},  # small l
    2: {"l": 65536},  # large l
}[CASE_SELECTOR]
l = case_params["l"]
a = rng.normal(loc=0, scale=1, size=l)
b = rng.normal(loc=0, scale=1, size=l)
a_centralized = a - a.mean(axis=0)
b_centralized = b - b.mean(axis=0)
ATA = 1 / np.sqrt((a_centralized.T.dot(a_centralized) ** 2).sum())
BTB = 1 / np.sqrt((b_centralized.T.dot(b_centralized) ** 2).sum())

bitsize = lambda x: np.ceil(np.log2(x))
get_closest_power_of_two = lambda x: int(2 ** (bitsize(x)))


def get_CKKS_context_scalar_prod(
    l: int, sec: int = 128, use_n_min: bool = True
) -> Pyfhel:
    """
    Returns the best context parameters to compute scalar product in CKKS scheme.

    The important context parameters to set are:
    - n: the polynomial modulus degree (= 2*n_slots)

    *Optimal n*: Chosen among {2**12, 2**13, 2**14, 2**15}.
        The bigger n, the more secure the scheme, but the slower the computations.
        It might be faster to use n<l and have multiple ciphertexts pervector.

    Arguments:
        l: vector length
        v_max: max element value

    Returns:
        Pyfhel: context to perform homomorphic encryption
    """
    # > OPTIMAL n
    n_min = 2**14
    if use_n_min:
        n = n_min  # use n_min regardless of l
    elif 2 * l < n_min:
        n = n_min  # Smallest
    elif 2 * l > 2**15:
        n = 2**15  # Largest
    else:
        n = get_closest_power_of_two(2 * l)

    context_params = {
        "scheme": "CKKS",
        "n": n,  # Poly modulus degree. BFV ptxt is a n//2 by 2 matrix.
        "sec": sec,  # Security level.
        "scale": 2**30,
        "qi_sizes": [60] + 10 * [30] + [60],  # Max number of multiplications = 1
    }
    HE = Pyfhel(context_params)
    return HE


HE = get_CKKS_context_scalar_prod(l, sec=128, use_n_min=True)
HE.keyGen()
HE.relinKeyGen()
HE.rotateKeyGen()

ctxt_a = [
    HE.encrypt(a_centralized[j : j + HE.get_nSlots()])
    for j in range(0, l, HE.get_nSlots())
]
ctxt_b = [
    HE.encrypt(b_centralized[j : j + HE.get_nSlots()])
    for j in range(0, l, HE.get_nSlots())
]
ctxt_a_transposed = [
    HE.encrypt(a_centralized.T[j : j + HE.get_nSlots()])
    for j in range(0, l, HE.get_nSlots())
]
ctxt_b_transposed = [
    HE.encrypt(b_centralized.T[j : j + HE.get_nSlots()])
    for j in range(0, l, HE.get_nSlots())
]
ctxt_ATA = HE.encrypt(ATA)
ctxt_BTB = HE.encrypt(BTB)

cka_ab = cka(
    ctxt_a, ctxt_b_transposed, ctxt_ATA, ctxt_BTB, HE, crypt=True
)  
print(HE.decrypt(cka_ab)[0])


ValueError Traceback (most recent call last)
in <cell line: 133>()
131 ctxt_BTB = HE.encrypt(BTB)
132
--> 133 cka_ab = cka(ctxt_a, ctxt_b_transposed, ctxt_ATA, ctxt_BTB, HE , crypt=True)#cka(ctxt_a, ctxt_b_transposed, ctxt_ATA, ctxt_BTB, HE , crypt=True)
134 print(HE.decrypt(cka_ab)[0])

1 frames
in cka_encrypted(X, Y, XTX, YTY, HE)
50 #print(bottom)
51
---> 52 result = bottom * top
53 #print("result encrypted")
54 #print(HE.decrypt(result))

Pyfhel/PyCtxt.pyx in Pyfhel.PyCtxt.PyCtxt.mul()

Pyfhel/Pyfhel.pyx in Pyfhel.Pyfhel.Pyfhel.multiply()

ValueError: encrypted1 and encrypted2 parameter mismatch
Setup:
This setup is being run in a Docker container, but this problem has presented itself when I run it using google colab as well

  • OS: ubuntu 20.04 LTS
  • Python: 3.10.13
  • C compiler version: GCC 9.4.0
  • Pyfhel Version: Latest github version
@ShokofehVS
Copy link

Hello, I have a feeling that your problem can be resolved by a solution described here.

@eduardo-sarmento
Copy link
Author

I don't think so, in the link that you shared in the error the list of available reescalings was empty, but in my case the list has reescalings, [30 60]. I also tested with more qi_sizes, up to 20*[30], but it did not have any effect on the error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants