tuneinsight / lattigo

A library for lattice-based multiparty homomorphic encryption in Go
Apache License 2.0
1.22k stars 181 forks source link

Usage of Rescale #40

Closed Dylan-yxn closed 4 years ago

Dylan-yxn commented 4 years ago

Hi, when I use Rescale() after Mul, the result is wrong. And it doesn't just happen occasionally. Here is my code:

evaluator.MulRelin(result,encIn[i],rlk,result)
fmt.Println(math.Log2(result.Scale()))
evaluator.Rescale(result,params.Scale,result)
fmt.Println(math.Log2(result.Scale()))

if we decrypt after MulRelin, we will get the corrext answer. And we decrypt after Rescale(), we will get a huge answer . The answer is different every time.

Here is one of answer: QMUTB_R)A%2DVJES0@AP B8

I wonder if my usage of Rescale () is wrong. How to use it correctly.

Dylan-yxn commented 4 years ago

Errors after Resclae() occur in the DCKKS scheme, but I have tested that they do not occur in the CKKS scheme.

ChristianMct commented 4 years ago

Hello,

Is it possible to provide a minimal code reproducing the behavior ? In particular, how are you decrypting the ciphertext ?

Dylan-yxn commented 4 years ago

Thank you for your reply. Here is my code:

....
//input
for j:= range pi.input{
    pi.input[j] = complex(1, 0)
}
/*CKG*/
...
/*RKG*/
...
    encoder := ckks.NewEncoder(params)
    encInputs := make([]*ckks.Ciphertext, N, N)
    encryptor := ckks.NewEncryptorFromPk(params, pk)
    for i := range encInputs {
        encInputs[i] = ckks.NewCiphertext(params, 1,params.MaxLevel(),params.Scale)
    }

    pt := ckks.NewPlaintext(params,params.MaxLevel(),params.Scale)
    for i, pi := range P {
        encoder.Encode(pt,pi.input,slots)
        encryptor.Encrypt(pt, encInputs[i])
    }

    evaluator := ckks.NewEvaluator(params)

    /*caculate*/
    result := encInputs[0]
    evaluator.MulRelin(result,encInputs[1],rlk,result)
    fmt.Println(math.Log2(result.Scale()))
    evaluator.Rescale(result,params.Scale,result)
    fmt.Println(math.Log2(result.Scale()))

        /*CKS*/
    zero := params.NewPolyQ()
    cksCombined := cks.AllocateShare()
    for _, pi := range P[1:] {
        cks.GenShare(pi.sk.Get(), zero, result, pi.cksShare)
    }
    encOut := ckks.NewCiphertext(params, 1,params.MaxLevel(),params.Scale)
    for _, pi := range P {
        cks.AggregateShares(pi.cksShare, cksCombined, cksCombined)
    }
    cks.KeySwitch(cksCombined,result, encOut)

       /*decrypt*/
    decryptor := ckks.NewDecryptor(params, P[0].sk)
    ptres := ckks.NewPlaintext(params,params.MaxLevel(),params.Scale)
    decryptor.Decrypt(encOut, ptres)
    res := encoder.Decode(ptres,slots)
    fmt.Printf(" %6f %6f %6f %6f %6f\n",
        round(res[0]), round(res[1]), round(res[2]), round(res[3]), round(res[4]))

If I didn't use Rescale (), I would get the correct answer, but I got the following answer after using: IKY1F}X`MBIH%Y6I6F%31VG

Pro7ech commented 4 years ago

Thank you very much. I'll take a look and get back to you as soon as I figured out what is going on.

Pro7ech commented 4 years ago

There is something I do not understand in your code. You have

The CKS already decrypts the ciphertext if you switch to the key zero, therefor all you need to to is to call encOut.Plaintext() to switch the element to a type plaintext and be able to decode it.

Dylan-yxn commented 4 years ago

Thanks for your reminder. res := encoder.Decode(encOut.Plaintext(),slots)

But after decrypting, the answer still has the same error.

Pro7ech commented 4 years ago

Could you give me a link go your entire go file? It will be easier for me to find where the bug is occurring

Dylan-yxn commented 4 years ago

Here is my code: https://github.com/Dylan-yxn/examples_dckks

Pro7ech commented 4 years ago

I found what was going wrong and why the rescale made it decrypt bad.

First, I was wrong, your decryption code was correct my bad for that, it was partially decrypting to the secret-key of P[0], and then P[0] would finish the decryption with his own key. You can revert the code to its previous state.

Then the bad decryption is occurring because

encOut := ckks.NewCiphertext(params, 1, params.MaxLevel(), params.Scale)

is created at max level. But the level of the ciphertext after you rescale is reduced by one (this is also why it was working fine without rescale), so instead you should use

encOut := ckks.NewCiphertext(params, 1, result.Level(), params.Scale)

Tell me if it fixes it

Dylan-yxn commented 4 years ago

I tried: encOut := ckks.NewCiphertext(params, 1 ,result.Level(),result.Scale()) and encOut := ckks.NewCiphertext(params, 1 ,result.Level(),params.Scale) But it didn't work. QYN1}88IIVH9Y{MX7HF3J%I

Pro7ech commented 4 years ago

Did you revert the code to its original decryption state? Because its working fine for me on the code that you provided.

Dylan-yxn commented 4 years ago

Thank you for your explanation. It can now be decrypted normally.