我对密文和结尾的正方形进行了一系列计算。问题是,即使有足够的噪声预算来执行平方和线性化(在操作之前和之后),当我解密它时,也会得到不正确的结果。
奇怪的是,如果我解密并解码,然后再次使用新的密文(即在平方之前的数字)再次编码和加密,则计算将正确执行。
我不明白问题出在哪里,因为如果设置的参数有误,那么无论如何我都会有不正确的结果。
我指定我使用分数编码器,其中整数部分的多项式系数为64,而分数部分的精度为32位(在基数3中),并且平方之前的所有计算都是在Ciphertext和Plaintext之间执行的。
这是我的意思的示例:
#include <vector>
#include "seal/seal.h"
using namespace std;
using namespace seal;
int main(int argc, char const *argv[])
{
//Set parameters
EncryptionParameters parms;
parms.set_poly_modulus("1x^4096 + 1");
parms.set_coeff_modulus(coeff_modulus_128(4096));
parms.set_plain_modulus(1<<20);
SEALContext context(parms);
KeyGenerator keygen(context);
PublicKey public_key = keygen.public_key();
SecretKey secret_key = keygen.secret_key();
EvaluationKeys ev_keys16;
keygen.generate_evaluation_keys(16, ev_keys16);
Encryptor encryptor(context, public_key);
Evaluator evaluator(context);
Decryptor decryptor(context, secret_key);
FractionalEncoder fraencoder(context.plain_modulus(), context.poly_modulus(), 64, 32, 3);
float data=0.5;
float weight= 1.5;
//encrypt data and encode weight
Ciphertext encrypted_data;
encryptor.encrypt(fraencoder.encode(data),encrypted_data);
cout<<"Noise budget in a freshly encrypted: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;
Plaintext encoded_weight=fraencoder.encode(weight);
//Operation: (0.5*1.5)*5=3.75
vector<Ciphertext> mul_vector(5);
for(int i=0;i<5;i++){
evaluator.multiply_plain(encrypted_data,encoded_weight,mul_vector[i]);
}
evaluator.add_many(mul_vector,encrypted_data);
cout<<"Noise budget after 5 plain multiplications and 4 additions: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;
//Operation: 3.75*4=15
vector<Ciphertext> add_vector(4);
for(int i=0;i<4;i++){
add_vector[i]= Ciphertext(encrypted_data);
}
evaluator.add_many(add_vector,encrypted_data);
cout<<"Noise budget after 4 additions: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;
//Operation: (15-1.5)*1.5=20.25
evaluator.sub_plain(encrypted_data,encoded_weight);
evaluator.multiply_plain(encrypted_data,encoded_weight);
cout<<"Noise budget after 1 plain sub and 1 plain multiplication: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;
//Operation: (20.25*1.5)*6=182.25
vector<Ciphertext> mul_vector2(6);
for(int i=0;i<6;i++){
evaluator.multiply_plain(encrypted_data,encoded_weight,mul_vector2[i]);
}
evaluator.add_many(mul_vector2,encrypted_data);
cout<<"Noise budget after 6 plain multiplications and 5 additions: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;
// here I decrypt, decode and encrypt again, to obtain the right result
Plaintext tmp;
float res;
//If I remove the following 4 lines the final result is incorrect
decryptor.decrypt(encrypted_data,tmp);
res = fraencoder.decode(tmp);
cout<<"Decrypted result before square: "<<res<<endl;
encryptor.encrypt(fraencoder.encode(res),encrypted_data);
//182.25^2=33215.1
evaluator.square(encrypted_data);
evaluator.relinearize(encrypted_data,ev_keys16);
cout<<"Noise budget after square and relianearization: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;
decryptor.decrypt(encrypted_data,tmp);
res= fraencoder.decode(tmp);
cout<<res<<endl;
return 0;
}
我想念什么?
答案 0 :(得分:3)
问题是您的plain_modulus
太小,无法进行此计算。
如果在末尾(tmp
上打印出tmp.to_string()
,您会发现它的系数很大。请注意,这些系数的模数为plain_modulus
,因此许多系数看起来会很大。但是,res
作为整数的无穷范数(即,如果使用足够大的plain_modulus
)为266441508,仅低于2 29 。由于您的plain_modulus
只有2 20 ,因此最后您将得到不正确的结果。重新编码会有所帮助,因为在上一次计算之前系数仍然不太大,并且对多项式进行重新编码会将系数降低到无穷范数1(在您的情况下为base = 3)。
解决方案是将plain_modulus
增加到至少2 29 。当然,这将导致更多的噪声增长,并且您已经非常接近噪声溢出,但是仍然可以使用。