tuneinsight/lattigo

Question: issue with RotateColumnsNew function in v5

Closed this issue · 4 comments

Hi Tuneinsight team,

Thanks for the great library! I have a question regarding the differences of the Rotate function between v4 and v5.

I was trying out the RotateColumnsNew function in v5 and the result seems incorrect, specifically, I did

galEls := 5
galk := kgen.GenGaloisKeyNew(galEls, Sk)
evk := rlwe.NewMemEvaluationKeySet(rlk, galk)
evaluator := heint.NewEvaluator(params, evk)

and it gave me an all-zero vector as the rotated result (for any input vectors).

However, the Rotate function is correct in v4, if I did the following:

galEls := params.GaloisElementsForMerge()
rtks := kgen.GenRotationKeys(galEls, Sk)
evaluator := bgv.NewEvaluator(params, rlwe.EvaluationKey{Rtks: rtks})

This gave me the correct rotated result.

It would be great to know if there is any steps I'm missing in v5 that causes the incorrect result. I also really appreciate if you can give an example related to rotations for bgv in v5!

Best,
Yiping

Hi @Yiping106283, could you please provide a self contained main.go that reproduces the issue?

Also be sure to check the error that might be returned by the evaluator.

Also be sure to check the error that might be returned by the evaluator.

Thanks for the hint! Just figured this out.
I have another question though about generating Galois keys, so pasting my main.go here:

package main

import (
	"fmt"

	"github.com/tuneinsight/lattigo/v5/core/rlwe"
	"github.com/tuneinsight/lattigo/v5/he/heint"
)

func pir() {
	// Creating encryption parameters from a default params with logN=14, logQP=438 with a plaintext modulus T=65929217
	params, err := heint.NewParametersFromLiteral(heint.ParametersLiteral{
		LogN:             14,
		LogQ:             []int{56, 55, 55, 54, 54, 54},
		LogP:             []int{55, 55},
		PlaintextModulus: 0x3ee0001,
	})
	if err != nil {
		panic(err)
	}

	encoder := heint.NewEncoder(params)
	kgen := rlwe.NewKeyGenerator(params)
	Sk, _ := kgen.GenKeyPairNew()

	decryptor := rlwe.NewDecryptor(params, Sk)
	encryptorSk := rlwe.NewEncryptor(params, Sk)

	// Relinearization Key
	rlk := kgen.GenRelinearizationKeyNew(Sk)

	// function from v4: 
        // galEls := params.GaloisElementsForMerge()
	// galEls := []uint64{5, 25, 625, 30177, 28609, 28545, 7937, 15873, 31745, 30721, 28673, 24577, 16385, 32767}
        // question: passing the argument galEls as a list doesn't seem to work here
	galk := kgen.GenGaloisKeyNew(5, Sk)
	evk := rlwe.NewMemEvaluationKeySet(rlk, galk)
	evaluator := heint.NewEvaluator(params, evk)

	// initialize an array
	lenArray := 1 << params.LogN()
	myArray := make([]uint64, 1<<params.LogN())
	for i := 0; i < lenArray/2; i++ {
		myArray[(i << 1)] = uint64((i << 1))
		myArray[(i<<1)+1] = uint64((i << 1) + 1)
	}

	myPlaintext := heint.NewPlaintext(params, params.MaxLevel())
	if err := encoder.Encode(myArray, myPlaintext); err != nil {
		panic(err)
	}

	myCiphertext, err := encryptorSk.EncryptNew(myPlaintext)
	if err != nil {
		panic(err)
	}

	// square
	myCiphertext, err = evaluator.MulRelinNew(myCiphertext, myCiphertext)
	if err != nil {
		panic(err)
	}

	// question: if wanting to rotate for any value, e.g., 1, not just 1
	myCiphertext, err = evaluator.RotateColumnsNew(myCiphertext, 3)
	if err != nil {
		panic(err)
	}

	evaluator.Rescale(myCiphertext, myCiphertext)

	result := make([]uint64, params.MaxSlots())
	if err := encoder.Decode(decryptor.DecryptNew(myCiphertext), result); err != nil {
		panic(err)
	}

	fmt.Println("my array = ", myArray[0:10])
	fmt.Println("result = ", result[0:10])

}

func main() {

	pir()
}

I marked the two question in comments, more specifically, passing the uint64 array galEls to the kgen.GenGaloisKeyNew function doesn't seem to work. Is there a way to do this in v5?

The method GenGaloisKeysNew takes an array of Galois elements

I see! One last question:

galEls := []uint64{5, 25, 625, 30177, 28609, 28545, 7937, 15873, 31745, 30721, 28673, 24577, 16385, 32767}
galk := kgen.GenGaloisKeysNew(galEls, Sk)
evk := rlwe.NewMemEvaluationKeySet(rlk, galk)
evaluator := heint.NewEvaluator(params, evk)

This doesn't allow the type []*rlwe.GaloisKey as the error message showed:

"cannot use galk (variable of type []*rlwe.GaloisKey) as *rlwe.GaloisKey value in argument to rlwe.NewMemEvaluationKeySet"

Should I change the way to set evk?

Just noticed that I can pass in each of the galks into the function.

Thanks for anwering!