УПЛОТНЕНИЕ: неправильная расшифровка после квадратной операции, даже если зашифрованный текст имеет больший, чем нулевой бюджет шума

У меня есть серия расчетов на зашифрованный текст и квадрат в конце. Проблема заключается в том, что даже если имеется достаточный бюджет шума для выполнения квадрата и перелинеаризации (как до, так и после операции), при расшифровке я получаю неверный результат.

Странно то, что, если я расшифрую и раскодирую, а затем закодирую и снова зашифрую в новом зашифрованном виде, число перед квадратом вычисление будет выполнено правильно.

Я не понимаю, в чем проблема, так как, если заданы неверные параметры, я все равно получу неверный результат.

Я указываю, что я использую Fractional Encoder с 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;
}

Что мне не хватает?

2

Решение

Проблема в том, что ваш plain_modulus слишком мало для этого вычисления.

Если вы распечатываете tmp в конце (tmp.to_string()) вы увидите, что он имеет очень большие коэффициенты. Обратите внимание, что эти коэффициенты по модулю plain_modulus ожидается, что многие из них будут выглядеть большими. Тем не менее, бесконечность норма res как целое число (т.е. если вы используете достаточно большой plain_modulus) 266441508, что чуть ниже 229. Так как ваш plain_modulus только 220, в итоге вы получите неправильные результаты. Ваше перекодирование помогает, потому что перед последними вычислениями коэффициенты все еще не слишком велики, и перекодирование полинома понижает коэффициенты обратно к норме бесконечности 1 (в вашем случае с base = 3).

Решение состоит в том, чтобы увеличить plain_modulus по крайней мере, 229. Конечно, это приведет к большему росту шума, и вы уже будете очень близко к шумовому переполнению, но это все равно будет работать.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]